Subversion Repositories Projects

Rev

Rev 2289 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2287 - 1

2
namespace GMap.NET.MapProviders
3
{
4
    using System;
5
    using GMap.NET.Projections;
6
    using System.Security.Cryptography;
7
    using System.Diagnostics;
8
    using System.Net;
9
    using System.IO;
10
    using System.Text.RegularExpressions;
11
    using System.Threading;
12
    using GMap.NET.Internals;
13
    using System.Collections.Generic;
14
    using System.Globalization;
15
    using System.Xml;
16
    using System.Text;
17
#if PocketPC
18
    using OpenNETCF.Security.Cryptography;
19
#endif
20
 
21
    public abstract class GoogleMapProviderBase : GMapProvider, RoutingProvider, GeocodingProvider, DirectionsProvider
22
    {
23
        public GoogleMapProviderBase()
24
        {
25
            MaxZoom = null;
26
            RefererUrl = string.Format("http://maps.{0}/", Server);
27
            Copyright = string.Format("©{0} Google - Map data ©{0} Tele Atlas, Imagery ©{0} TerraMetrics", DateTime.Today.Year);
28
        }
29
 
30
        public readonly string ServerAPIs /* ;}~~ */ = Stuff.GString(/*{^_^}*/"9gERyvblybF8iMuCt/LD6w=="/*d{'_'}b*/);
31
        public readonly string Server /* ;}~~~~ */ = Stuff.GString(/*{^_^}*/"gosr2U13BoS+bXaIxt6XWg=="/*d{'_'}b*/);
32
        public readonly string ServerChina /* ;}~ */ = Stuff.GString(/*{^_^}*/"gosr2U13BoTEJoJJuO25gQ=="/*d{'_'}b*/);
33
        public readonly string ServerKorea /* ;}~~ */ = Stuff.GString(/*{^_^}*/"8ZVBOEsBinzi+zmP7y7pPA=="/*d{'_'}b*/);
34
        public readonly string ServerKoreaKr /* ;}~ */ = Stuff.GString(/*{^_^}*/"gosr2U13BoQyz1gkC4QLfg=="/*d{'_'}b*/);
35
 
36
        public string SecureWord = "Galileo";
37
 
38
        /// <summary>
39
        /// Your application's API key, obtained from the Google Developers Console.
40
        /// This key identifies your application for purposes of quota management. 
41
        /// Must provide either API key or Maps for Work credentials.
42
        /// </summary>
43
        public string ApiKey = string.Empty;
44
 
45
        #region GMapProvider Members
46
        public override Guid Id
47
        {
48
            get
49
            {
50
                throw new NotImplementedException();
51
            }
52
        }
53
 
54
        public override string Name
55
        {
56
            get
57
            {
58
                throw new NotImplementedException();
59
            }
60
        }
61
 
62
        public override PureProjection Projection
63
        {
64
            get
65
            {
66
                return MercatorProjection.Instance;
67
            }
68
        }
69
 
70
        GMapProvider [] overlays;
71
        public override GMapProvider [] Overlays
72
        {
73
            get
74
            {
75
                if (overlays == null)
76
                {
77
                    overlays = new GMapProvider [] { this };
78
                }
79
                return overlays;
80
            }
81
        }
82
 
83
        public override PureImage GetTileImage(GPoint pos, int zoom)
84
        {
85
            throw new NotImplementedException();
86
        }
87
        #endregion
88
 
89
        public bool TryCorrectVersion = true;
90
        static bool init = false;
91
 
92
        public override void OnInitialized()
93
        {
94
            if (!init && TryCorrectVersion)
95
            {              
96
                string url = string.Format("https://maps.{0}/maps/api/js?client=google-maps-lite&amp;libraries=search&amp;language=en&amp;region=", ServerAPIs);
97
                try
98
                {
99
                    string html = GMaps.Instance.UseUrlCache ? Cache.Instance.GetContent(url, CacheType.UrlCache, TimeSpan.FromHours(8)) : string.Empty;
100
 
101
                    if (string.IsNullOrEmpty(html))
102
                    {
103
                        html = GetContentUsingHttp(url);
104
                        if (!string.IsNullOrEmpty(html))
105
                        {
106
                            if (GMaps.Instance.UseUrlCache)
107
                            {
108
                                Cache.Instance.SaveContent(url, CacheType.UrlCache, html);
109
                            }
110
                        }
111
                    }
112
 
113
                    if (!string.IsNullOrEmpty(html))
114
                    {
115
                        #region -- match versions --
116
                        Regex reg = new Regex(string.Format(@"https?://mts?\d.{0}/maps/vt\?lyrs=m@(\d*)", Server), RegexOptions.IgnoreCase);
117
                        Match mat = reg.Match(html);
118
                        if (mat.Success)
119
                        {
120
                            GroupCollection gc = mat.Groups;
121
                            int count = gc.Count;
122
                            if (count > 0)
123
                            {
124
                                string ver = string.Format("m@{0}", gc [1].Value);
125
                                string old = GMapProviders.GoogleMap.Version;
126
 
127
                                GMapProviders.GoogleMap.Version = ver;
128
                                GMapProviders.GoogleChinaMap.Version = ver;
129
 
130
                                string verh = string.Format("h@{0}", gc [1].Value);
131
                                string oldh = GMapProviders.GoogleHybridMap.Version;
132
 
133
                                GMapProviders.GoogleHybridMap.Version = verh;
134
                                GMapProviders.GoogleChinaHybridMap.Version = verh;
135
#if DEBUG
136
                                Debug.WriteLine("GMapProviders.GoogleMap.Version: " + ver + ", " + (ver == old ? "OK" : "old: " + old + ", consider updating source"));
137
                                Debug.WriteLine("GMapProviders.GoogleHybridMap.Version: " + verh + ", " + (verh == oldh ? "OK" : "old: " + oldh + ", consider updating source"));
138
 
139
                                if (Debugger.IsAttached && ver != old)
140
                                {
141
                                    Thread.Sleep(1111);
142
                                }
143
#endif
144
                            }
145
                        }
146
 
147
                        reg = new Regex(string.Format(@"https?://khms?\d.{0}/kh\?v=(\d*)", Server), RegexOptions.IgnoreCase);
148
                        mat = reg.Match(html);
149
                        if (mat.Success)
150
                        {
151
                            GroupCollection gc = mat.Groups;
152
                            int count = gc.Count;
153
                            if (count > 0)
154
                            {
155
                                string ver = gc [1].Value;
156
                                string old = GMapProviders.GoogleSatelliteMap.Version;
157
 
158
                                GMapProviders.GoogleSatelliteMap.Version = ver;
159
                                GMapProviders.GoogleKoreaSatelliteMap.Version = ver;
160
                                GMapProviders.GoogleChinaSatelliteMap.Version = "s@" + ver;
161
#if DEBUG
162
                                Debug.WriteLine("GMapProviders.GoogleSatelliteMap.Version: " + ver + ", " + (ver == old ? "OK" : "old: " + old + ", consider updating source"));
163
                                if (Debugger.IsAttached && ver != old)
164
                                {
165
                                    Thread.Sleep(1111);
166
                                }
167
#endif
168
                            }
169
                        }
170
 
171
                        reg = new Regex(string.Format(@"https?://mts?\d.{0}/maps/vt\?lyrs=t@(\d*),r@(\d*)", Server), RegexOptions.IgnoreCase);
172
                        mat = reg.Match(html);
173
                        if (mat.Success)
174
                        {
175
                            GroupCollection gc = mat.Groups;
176
                            int count = gc.Count;
177
                            if (count > 1)
178
                            {
179
                                string ver = string.Format("t@{0},r@{1}", gc [1].Value, gc [2].Value);
180
                                string old = GMapProviders.GoogleTerrainMap.Version;
181
 
182
                                GMapProviders.GoogleTerrainMap.Version = ver;
183
                                GMapProviders.GoogleChinaTerrainMap.Version = ver;
184
#if DEBUG
185
                                Debug.WriteLine("GMapProviders.GoogleTerrainMap.Version: " + ver + ", " + (ver == old ? "OK" : "old: " + old + ", consider updating source"));
186
                                if (Debugger.IsAttached && ver != old)
187
                                {
188
                                    Thread.Sleep(1111);
189
                                }
190
#endif
191
                            }
192
                        }
193
                        #endregion
194
                    }
195
 
196
                    init = true; // try it only once
197
                }
198
                catch (Exception ex)
199
                {
200
                    Debug.WriteLine("TryCorrectGoogleVersions failed: " + ex.ToString());
201
                }
202
            }
203
        }
204
 
205
        internal void GetSecureWords(GPoint pos, out string sec1, out string sec2)
206
        {
207
            sec1 = string.Empty; // after &x=...
208
            sec2 = string.Empty; // after &zoom=...
209
            int seclen = (int)((pos.X * 3) + pos.Y) % 8;
210
            sec2 = SecureWord.Substring(0, seclen);
211
            if (pos.Y >= 10000 && pos.Y < 100000)
212
            {
213
                sec1 = Sec1;
214
            }
215
        }
216
 
217
        static readonly string Sec1 = "&s=";
218
 
219
        #region RoutingProvider Members
220
 
221
        public MapRoute GetRoute(PointLatLng start, PointLatLng end, bool avoidHighways, bool walkingMode, int Zoom)
222
        {
223
            string tooltip;
224
            int numLevels;
225
            int zoomFactor;
226
            MapRoute ret = null;
227
            List<PointLatLng> points = GetRoutePoints(MakeRouteUrl(start, end, LanguageStr, avoidHighways, walkingMode), Zoom, out tooltip, out numLevels, out zoomFactor);
228
            if (points != null)
229
            {
230
                ret = new MapRoute(points, tooltip);
231
            }
232
            return ret;
233
        }
234
 
235
        public MapRoute GetRoute(string start, string end, bool avoidHighways, bool walkingMode, int Zoom)
236
        {
237
            string tooltip;
238
            int numLevels;
239
            int zoomFactor;
240
            MapRoute ret = null;
241
            List<PointLatLng> points = GetRoutePoints(MakeRouteUrl(start, end, LanguageStr, avoidHighways, walkingMode), Zoom, out tooltip, out numLevels, out zoomFactor);
242
            if (points != null)
243
            {
244
                ret = new MapRoute(points, tooltip);
245
            }
246
            return ret;
247
        }
248
 
249
        #region -- internals --
250
 
251
        string MakeRouteUrl(PointLatLng start, PointLatLng end, string language, bool avoidHighways, bool walkingMode)
252
        {
253
            string opt = walkingMode ? WalkingStr : (avoidHighways ? RouteWithoutHighwaysStr : RouteStr);
254
            return string.Format(CultureInfo.InvariantCulture, RouteUrlFormatPointLatLng, language, opt, start.Lat, start.Lng, end.Lat, end.Lng, Server);
255
        }
256
 
257
        string MakeRouteUrl(string start, string end, string language, bool avoidHighways, bool walkingMode)
258
        {
259
            string opt = walkingMode ? WalkingStr : (avoidHighways ? RouteWithoutHighwaysStr : RouteStr);
260
            return string.Format(RouteUrlFormatStr, language, opt, start.Replace(' ', '+'), end.Replace(' ', '+'), Server);
261
        }
262
 
263
        List<PointLatLng> GetRoutePoints(string url, int zoom, out string tooltipHtml, out int numLevel, out int zoomFactor)
264
        {
265
            List<PointLatLng> points = null;
266
            tooltipHtml = string.Empty;
267
            numLevel = -1;
268
            zoomFactor = -1;
269
            try
270
            {
271
                string route = GMaps.Instance.UseRouteCache ? Cache.Instance.GetContent(url, CacheType.RouteCache) : string.Empty;
272
 
273
                if (string.IsNullOrEmpty(route))
274
                {
275
                    route = GetContentUsingHttp(url);
276
 
277
                    if (!string.IsNullOrEmpty(route))
278
                    {
279
                        if (GMaps.Instance.UseRouteCache)
280
                        {
281
                            Cache.Instance.SaveContent(url, CacheType.RouteCache, route);
282
                        }
283
                    }
284
                }
285
 
286
                // parse values
287
                if (!string.IsNullOrEmpty(route))
288
                {
289
                    //{
290
                    //tooltipHtml:" (300\x26#160;km / 2 valandos 59 min.)",
291
                    //polylines:
292
                    //[{
293
                    //   id:"route0",
294
                    //   points:"cy~rIcvp`ClJ~v@jHpu@N|BB~A?tA_@`J@nAJrB|AhEf@h@~@^pANh@Mr@a@`@_@x@cBPk@ZiBHeDQ{C]wAc@mAqCeEoA_C{@_Cy@iDoEaW}AsJcJ}t@iWowB{C_Vyw@gvGyTyjBu@gHwDoZ{W_zBsX}~BiA_MmAyOcAwOs@yNy@eTk@mVUmTE}PJ_W`@cVd@cQ`@}KjA_V`AeOn@oItAkOdAaKfBaOhDiVbD}RpBuKtEkTtP}q@fr@ypCfCmK|CmNvEqVvCuQ`BgLnAmJ`CgTpA_N~@sLlBwYh@yLp@cSj@e]zFkzKHaVViSf@wZjFwqBt@{Wr@qS`AaUjAgStBkYrEwe@xIuw@`Gmj@rFok@~BkYtCy_@|KccBvBgZjC}[tD__@pDaYjB_MpBuLhGi[fC}KfFcSnEkObFgOrFkOzEoLt[ys@tJeUlIsSbKqXtFiPfKi]rG_W|CiNhDkPfDuQlDoShEuXrEy[nOgiAxF{`@|DoVzFk[fDwPlXupA~CoPfDuQxGcd@l@yEdH{r@xDam@`AiWz@mYtAq~@p@uqAfAqx@|@kZxA}^lBq\\|Be\\lAaO~Dm`@|Gsj@tS_~AhCyUrCeZrByWv@uLlUiyDpA}NdHkn@pGmb@LkAtAoIjDqR`I{`@`BcH|I_b@zJcd@lKig@\\_CbBaIlJ}g@lIoj@pAuJtFoh@~Eqs@hDmv@h@qOfF{jBn@gSxCio@dAuQn@gIVoBjAiOlCqWbCiT`PekAzKiu@~EgYfIya@fA{ExGwWnDkMdHiU|G}R`HgQhRsa@hW}g@jVsg@|a@cbAbJkUxKoYxLa_@`IiZzHu[`DoOXsBhBuJbCwNdBaL`EkYvAwM`CeVtEwj@nDqj@BkAnB{YpGgeAn@eJ`CmYvEid@tBkQpGkd@rE}UxB}JdJo_@nDcNfSan@nS}j@lCeIvDsMbC{J|CyNbAwFfCgPz@uGvBiSdD}`@rFon@nKaqAxDmc@xBuT|Fqc@nC_PrEcUtC_MpFcT`GqQxJmXfXwq@jQgh@hBeGhG_U|BaK|G}[nRikAzIam@tDsYfE}^v@_MbAwKn@oIr@yLrBub@jAoa@b@sRdDmjBx@aZdA}XnAqVpAgTlAqPn@oGvFye@dCeRzGwb@xT_}A`BcPrAoOvCad@jAmXv@eV`BieA~@a[fBg_@`CiZ~A_OhHqk@hHcn@tEwe@rDub@nBoW~@sN|BeZnAgMvDm\\hFs^hSigArFaY`Gc\\`C}OhD}YfByQdAaNbAkOtOu~Cn@wKz@uLfCeY|CkW~B}OhCmO|AcI~A_IvDoPpEyPdImWrDuKnL_YjI{Ptl@qfAle@u|@xI}PbImQvFwMbGgOxFkOpdAosCdD_KxGsU|E}RxFcXhCwNjDwTvBiPfBqOrAyMfBcTxAaVhAwVrCy_Al@iPt@_OtA}Q`AuJ`AgIzAkK`EoUtBsJhCaKxCaKdDaKhQeg@jGiRfGaSrFyR`HsWvL}f@xp@grC`Sq|@pEsVdAoGjF{XlkAgwHxHgj@|Jex@fg@qlEjQs{AdHwh@zDkVhEkVzI_e@v}AgzHpK_l@tE}YtEy[rC}TpFme@jg@cpEbF{d@~BoXfBqUbAyOx@yN|Ao]bAo[tIazC`@iLb@aJ~AkWbBgRdBgPjA{IdCePlAmHfBmJdCiL~CuM|DoNxhDezKdDkLvBoInFqVbCuMxBqNnAeJ~CwXdBoSb^crElFsl@`Dy[zDu^xBiRzc@aaE|Fsd@vCkShDmTpG}^lD}QzDoR|zAcdHvIob@dKoj@jDmSlKiq@xVacBhEqXnBqL|Ga^zJke@`y@ktD~Mop@tP}_AdOg`AtCiQxCyOlDkPfDoN`GiTfGkRjEwLvEsL|HkQtEkJdE{HrwAkaCrT{a@rpDiuHtE_KvLuV|{AwaDzAqCb@mAf{Ac`D~FqL~y@_fBlNmZbGaNtF}Mpn@s~AlYss@dFgK|DoGhBoCrDuE~AcBtGaGnByAnDwBnCwAfDwAnFaBjGkA~[{E`iEkn@pQaDvIwBnIiCl\\qLn}J{pDhMcGrFcDhGeEvoDehC|AsArCwChBaC`C_EzC_HbBcFd@uB`@qAn@gDdB}Kz@}Hn@iPjByx@jDcvAj@}RDsEn@yTv@a]VcPtEamFBcHT_LNkEdAiShDsi@`GudAbFgx@`@iKdP}yFhBgs@p@yRjCo_AJwCXeEb@uEz@_H|@yEnBqHrCiIpAmE`o@qhBxC_IjIuVdIcXh{AgmG`i@_{BfCuLrhAssGfFeXxbBklInCsN|_AoiGpGs_@pl@w}Czy@_kEvG{]h}@ieFbQehAdHye@lPagA|Eu\\tAmI|CwWjn@mwGj@eH|]azFl@kPjAqd@jJe|DlD}vAxAeh@@eBvVk}JzIkqDfE_aBfA{YbBk[zp@e}LhAaObCeUlAuIzAeJrb@q`CjCcOnAaIpBwOtBkTjDsg@~AiPvBwOlAcH|AkIlCkLlYudApDoN`BgHhBaJvAeIvAqJbAuHrBqQbAsLx@oL`MwrCXkFr@uJh@{FhBsOvXwoB|EqVdBmHxC}KtCcJtDgKjDoIxE}JdHcMdCuDdIoKlmB}|BjJuMfFgIlE{HlEyIdEeJ~FaOvCgInCuI`EmN`J}]rEsP`EuMzCoIxGwPpi@cnAhGgPzCiJvFmRrEwQbDyOtCoPbDwTxDq\\rAsK`BgLhB{KxBoLfCgLjDqKdBqEfEkJtSy^`EcJnDuJjAwDrCeK\\}AjCaNr@qEjAaJtNaqAdCqQ`BsItS}bAbQs{@|Kor@xBmKz}@}uDze@{zAjk@}fBjTsq@r@uCd@aDFyCIwCWcCY}Aq_@w|A{AwF_DyHgHwOgu@m_BSb@nFhL",
295
                    //   levels:"B?@?????@?@???A???@?@????@??@????????@????@???A????@????@??@???@??@???A???@??@???A??@???@????A??@???@??@????@??@???@????@???@??A@?@???@????A????@??@?@???@???????@??@?@????@????@?A??@???@????@??@?A??????@???????@??A???@??@???@??@????@??@?@?????@?@?A?@????@???@??@??@????@?@??@?@??@??????@???@?@????@???B???@??@??????@??@???A?????@????@???A??@??????@??@??A?@???@???@??A????@???@???@????A????@@??A???@???@??@??A????@??????@??@???@???B????@?@????????@????@????A?????@????@??A???@???@???B???@?????@???@????@????@???A???????@??A@??@?@??@@?????A?@@????????@??@?A????@?????@???@???@???@???@?@?A???@??@?@??@???@?????@???A??@???????@????@???@????@????@@???A????@?@??@?B",
296
                    //   numLevels:4,
297
                    //   zoomFactor:16
298
                    //}]
299
                    //}
300
 
301
                    #region -- title --
302
                    int tooltipEnd = 0;
303
                    {
304
                        int x = route.IndexOf("tooltipHtml:") + 13;
305
                        if (x >= 13)
306
                        {
307
                            tooltipEnd = route.IndexOf("\"", x + 1);
308
                            if (tooltipEnd > 0)
309
                            {
310
                                int l = tooltipEnd - x;
311
                                if (l > 0)
312
                                {
313
                                    tooltipHtml = route.Substring(x, l).Replace(@"\x26#160;", " ");
314
                                }
315
                            }
316
                        }
317
                    }
318
                    #endregion
319
 
320
                    #region -- points --
321
                    int pointsEnd = 0;
322
                    {
323
                        int x = route.IndexOf("points:", tooltipEnd >= 0 ? tooltipEnd : 0) + 8;
324
                        if (x >= 8)
325
                        {
326
                            pointsEnd = route.IndexOf("\"", x + 1);
327
                            if (pointsEnd > 0)
328
                            {
329
                                int l = pointsEnd - x;
330
                                if (l > 0)
331
                                {
332
                                    /*
333
                                    while(l % 5 != 0)
334
                                    {
335
                                       l--;
336
                                    }
337
                                    */
338
 
339
                                    points = new List<PointLatLng>();
340
                                    DecodePointsInto(points, route.Substring(x, l));
341
                                }
342
                            }
343
                        }
344
                    }
345
                    #endregion
346
 
347
                    #region -- levels --
348
                    string levels = string.Empty;
349
                    int levelsEnd = 0;
350
                    {
351
                        int x = route.IndexOf("levels:", pointsEnd >= 0 ? pointsEnd : 0) + 8;
352
                        if (x >= 8)
353
                        {
354
                            levelsEnd = route.IndexOf("\"", x + 1);
355
                            if (levelsEnd > 0)
356
                            {
357
                                int l = levelsEnd - x;
358
                                if (l > 0)
359
                                {
360
                                    levels = route.Substring(x, l);
361
                                }
362
                            }
363
                        }
364
                    }
365
                    #endregion
366
 
367
                    #region -- numLevel --
368
                    int numLevelsEnd = 0;
369
                    {
370
                        int x = route.IndexOf("numLevels:", levelsEnd >= 0 ? levelsEnd : 0) + 10;
371
                        if (x >= 10)
372
                        {
373
                            numLevelsEnd = route.IndexOf(",", x);
374
                            if (numLevelsEnd > 0)
375
                            {
376
                                int l = numLevelsEnd - x;
377
                                if (l > 0)
378
                                {
379
                                    numLevel = int.Parse(route.Substring(x, l));
380
                                }
381
                            }
382
                        }
383
                    }
384
                    #endregion
385
 
386
                    #region -- zoomFactor --
387
                    {
388
                        int x = route.IndexOf("zoomFactor:", numLevelsEnd >= 0 ? numLevelsEnd : 0) + 11;
389
                        if (x >= 11)
390
                        {
391
                            int end = route.IndexOf("}", x);
392
                            if (end > 0)
393
                            {
394
                                int l = end - x;
395
                                if (l > 0)
396
                                {
397
                                    zoomFactor = int.Parse(route.Substring(x, l));
398
                                }
399
                            }
400
                        }
401
                    }
402
                    #endregion
403
 
404
                    #region -- trim point overload --
405
                    if (points != null && numLevel > 0 && !string.IsNullOrEmpty(levels))
406
                    {
407
                        if (points.Count - levels.Length > 0)
408
                        {
409
                            points.RemoveRange(levels.Length, points.Count - levels.Length);
410
                        }
411
 
412
                        //http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/description.html
413
                        //
414
                        string allZlevels = "TSRPONMLKJIHGFEDCBA@?";
415
                        if (numLevel > allZlevels.Length)
416
                        {
417
                            numLevel = allZlevels.Length;
418
                        }
419
 
420
                        // used letters in levels string
421
                        string pLevels = allZlevels.Substring(allZlevels.Length - numLevel);
422
 
423
                        // remove useless points at zoom
424
                        {
425
                            List<PointLatLng> removedPoints = new List<PointLatLng>();
426
 
427
                            for (int i = 0; i < levels.Length; i++)
428
                            {
429
                                int zi = pLevels.IndexOf(levels [i]);
430
                                if (zi > 0)
431
                                {
432
                                    if (zi * numLevel > zoom)
433
                                    {
434
                                        removedPoints.Add(points [i]);
435
                                    }
436
                                }
437
                            }
438
 
439
                            foreach (var v in removedPoints)
440
                            {
441
                                points.Remove(v);
442
                            }
443
                            removedPoints.Clear();
444
                            removedPoints = null;
445
                        }
446
                    }
447
                    #endregion
448
                }
449
            }
450
            catch (Exception ex)
451
            {
452
                points = null;
453
                Debug.WriteLine("GetRoutePoints: " + ex);
454
            }
455
            return points;
456
        }
457
 
458
        static readonly string RouteUrlFormatPointLatLng = "http://maps.{6}/maps?f=q&output=dragdir&doflg=p&hl={0}{1}&q=&saddr=@{2},{3}&daddr=@{4},{5}";
459
        static readonly string RouteUrlFormatStr = "http://maps.{4}/maps?f=q&output=dragdir&doflg=p&hl={0}{1}&q=&saddr=@{2}&daddr=@{3}";
460
 
461
        static readonly string WalkingStr = "&mra=ls&dirflg=w";
462
        static readonly string RouteWithoutHighwaysStr = "&mra=ls&dirflg=dh";
463
        static readonly string RouteStr = "&mra=ls&dirflg=d";
464
 
465
        #endregion
466
 
467
        #endregion
468
 
469
        #region GeocodingProvider Members
470
 
471
        public GeoCoderStatusCode GetPoints(string keywords, out List<PointLatLng> pointList)
472
        {
473
            return GetLatLngFromGeocoderUrl(MakeGeocoderUrl(keywords, LanguageStr), out pointList);
474
        }
475
 
476
        public PointLatLng? GetPoint(string keywords, out GeoCoderStatusCode status)
477
        {
478
            List<PointLatLng> pointList;
479
            status = GetPoints(keywords, out pointList);
480
            return pointList != null && pointList.Count > 0 ? pointList [0] : (PointLatLng?)null;
481
        }
482
 
483
        /// <summary>
484
        /// NotImplemented
485
        /// </summary>
486
        /// <param name="placemark"></param>
487
        /// <param name="pointList"></param>
488
        /// <returns></returns>
489
        public GeoCoderStatusCode GetPoints(Placemark placemark, out List<PointLatLng> pointList)
490
        {
491
            throw new NotImplementedException("use GetPoints(string keywords...");
492
        }
493
 
494
        /// <summary>
495
        /// NotImplemented
496
        /// </summary>
497
        /// <param name="placemark"></param>
498
        /// <param name="status"></param>
499
        /// <returns></returns>
500
        public PointLatLng? GetPoint(Placemark placemark, out GeoCoderStatusCode status)
501
        {
502
            throw new NotImplementedException("use GetPoint(string keywords...");
503
        }
504
 
505
        public GeoCoderStatusCode GetPlacemarks(PointLatLng location, out List<Placemark> placemarkList)
506
        {
507
            return GetPlacemarkFromReverseGeocoderUrl(MakeReverseGeocoderUrl(location, LanguageStr), out placemarkList);
508
        }
509
 
510
        public Placemark? GetPlacemark(PointLatLng location, out GeoCoderStatusCode status)
511
        {
512
            List<Placemark> pointList;
513
            status = GetPlacemarks(location, out pointList);
514
            return pointList != null && pointList.Count > 0 ? pointList [0] : (Placemark?)null;
515
        }
516
 
517
        #region -- internals --
518
 
519
        // The Coogle Geocoding API: http://tinyurl.com/cdlj889
520
 
521
        string MakeGeocoderUrl(string keywords, string language)
522
        {
523
            return string.Format(CultureInfo.InvariantCulture, GeocoderUrlFormat, ServerAPIs, Uri.EscapeDataString(keywords).Replace(' ', '+'), language);
524
        }
525
 
526
        string MakeReverseGeocoderUrl(PointLatLng pt, string language)
527
        {
528
            return string.Format(CultureInfo.InvariantCulture, ReverseGeocoderUrlFormat, ServerAPIs, pt.Lat, pt.Lng, language);
529
        }
530
 
531
        GeoCoderStatusCode GetLatLngFromGeocoderUrl(string url, out List<PointLatLng> pointList)
532
        {
533
            var status = GeoCoderStatusCode.Unknow;
534
            pointList = null;
535
 
536
            try
537
            {
538
                string geo = GMaps.Instance.UseGeocoderCache ? Cache.Instance.GetContent(url, CacheType.GeocoderCache) : string.Empty;
539
 
540
                bool cache = false;
541
 
542
                if (string.IsNullOrEmpty(geo))
543
                {
544
                    string urls = url;
545
 
546
                    // Must provide either API key or Maps for Work credentials.
547
                    if (!string.IsNullOrEmpty(ClientId))
548
                    {
549
                        urls = GetSignedUri(url);
550
                    }
551
                    else if (!string.IsNullOrEmpty(ApiKey))
552
                    {
553
                        urls += "&key=" + ApiKey;
554
                    }
555
 
556
                    geo = GetContentUsingHttp(urls);
557
 
558
                    if (!string.IsNullOrEmpty(geo))
559
                    {
560
                        cache = true;
561
                    }
562
                }
563
 
564
                if (!string.IsNullOrEmpty(geo))
565
                {
566
                    if (geo.StartsWith("<?xml"))
567
                    {
568
                        #region -- xml response --
569
                        //<?xml version="1.0" encoding="UTF-8"?>
570
                        //<GeocodeResponse>
571
                        // <status>OK</status>
572
                        // <result>
573
                        //  <type>locality</type>
574
                        //  <type>political</type>
575
                        //  <formatted_address>Vilnius, Lithuania</formatted_address>
576
                        //  <address_component>
577
                        //   <long_name>Vilnius</long_name>
578
                        //   <short_name>Vilnius</short_name>
579
                        //   <type>locality</type>
580
                        //   <type>political</type>
581
                        //  </address_component>
582
                        //  <address_component>
583
                        //   <long_name>Vilniaus miesto savivaldyb??</long_name>
584
                        //   <short_name>Vilniaus m. sav.</short_name>
585
                        //   <type>administrative_area_level_2</type>
586
                        //   <type>political</type>
587
                        //  </address_component>
588
                        //  <address_component>
589
                        //   <long_name>Vilnius County</long_name>
590
                        //   <short_name>Vilnius County</short_name>
591
                        //   <type>administrative_area_level_1</type>
592
                        //   <type>political</type>
593
                        //  </address_component>
594
                        //  <address_component>
595
                        //   <long_name>Lithuania</long_name>
596
                        //   <short_name>LT</short_name>
597
                        //   <type>country</type>
598
                        //   <type>political</type>
599
                        //  </address_component>
600
                        //  <geometry>
601
                        //   <location>
602
                        //    <lat>54.6871555</lat>
603
                        //    <lng>25.2796514</lng>
604
                        //   </location>
605
                        //   <location_type>APPROXIMATE</location_type>
606
                        //   <viewport>
607
                        //    <southwest>
608
                        //     <lat>54.5677980</lat>
609
                        //     <lng>25.0243760</lng>
610
                        //    </southwest>
611
                        //    <northeast>
612
                        //     <lat>54.8325440</lat>
613
                        //     <lng>25.4814883</lng>
614
                        //    </northeast>
615
                        //   </viewport>
616
                        //   <bounds>
617
                        //    <southwest>
618
                        //     <lat>54.5677980</lat>
619
                        //     <lng>25.0243760</lng>
620
                        //    </southwest>
621
                        //    <northeast>
622
                        //     <lat>54.8325440</lat>
623
                        //     <lng>25.4814883</lng>
624
                        //    </northeast>
625
                        //   </bounds>
626
                        //  </geometry>
627
                        // </result>
628
                        // <result>
629
                        //  <type>airport</type>
630
                        //  <type>transit_station</type>
631
                        //  <type>establishment</type>
632
                        //  <formatted_address>Vilnius International Airport (VNO), 10A, Vilnius, Lithuania</formatted_address>
633
                        //  <address_component>
634
                        //   <long_name>Vilnius International Airport</long_name>
635
                        //   <short_name>Vilnius International Airport</short_name>
636
                        //   <type>establishment</type>
637
                        //  </address_component>
638
                        //  <address_component>
639
                        //   <long_name>10A</long_name>
640
                        //   <short_name>10A</short_name>
641
                        //   <type>street_number</type>
642
                        //  </address_component>
643
                        //  <address_component>
644
                        //   <long_name>Vilnius</long_name>
645
                        //   <short_name>Vilnius</short_name>
646
                        //   <type>locality</type>
647
                        //   <type>political</type>
648
                        //  </address_component>
649
                        //  <address_component>
650
                        //   <long_name>Vilniaus miesto savivaldyb??</long_name>
651
                        //   <short_name>Vilniaus m. sav.</short_name>
652
                        //   <type>administrative_area_level_2</type>
653
                        //   <type>political</type>
654
                        //  </address_component>
655
                        //  <address_component>
656
                        //   <long_name>Vilnius County</long_name>
657
                        //   <short_name>Vilnius County</short_name>
658
                        //   <type>administrative_area_level_1</type>
659
                        //   <type>political</type>
660
                        //  </address_component>
661
                        //  <address_component>
662
                        //   <long_name>Lithuania</long_name>
663
                        //   <short_name>LT</short_name>
664
                        //   <type>country</type>
665
                        //   <type>political</type>
666
                        //  </address_component>
667
                        //  <geometry>
668
                        //   <location>
669
                        //    <lat>54.6369440</lat>
670
                        //    <lng>25.2877780</lng>
671
                        //   </location>
672
                        //   <location_type>APPROXIMATE</location_type>
673
                        //   <viewport>
674
                        //    <southwest>
675
                        //     <lat>54.6158331</lat>
676
                        //     <lng>25.2723832</lng>
677
                        //    </southwest>
678
                        //    <northeast>
679
                        //     <lat>54.6538331</lat>
680
                        //     <lng>25.3034219</lng>
681
                        //    </northeast>
682
                        //   </viewport>
683
                        //   <bounds>
684
                        //    <southwest>
685
                        //     <lat>54.6158331</lat>
686
                        //     <lng>25.2723832</lng>
687
                        //    </southwest>
688
                        //    <northeast>
689
                        //     <lat>54.6538331</lat>
690
                        //     <lng>25.3034219</lng>
691
                        //    </northeast>
692
                        //   </bounds>
693
                        //  </geometry>
694
                        // </result>
695
                        //</GeocodeResponse>
696
 
697
                        #endregion
698
 
699
                        XmlDocument doc = new XmlDocument();
700
                        doc.LoadXml(geo);
701
 
702
                        XmlNode nn = doc.SelectSingleNode("//status");
703
                        if (nn != null)
704
                        {
705
                            if (nn.InnerText != "OK")
706
                            {
707
                                Debug.WriteLine("GetLatLngFromGeocoderUrl: " + nn.InnerText);
708
                            }
709
                            else
710
                            {
711
                                status = GeoCoderStatusCode.G_GEO_SUCCESS;
712
 
713
                                if (cache && GMaps.Instance.UseGeocoderCache)
714
                                {
715
                                    Cache.Instance.SaveContent(url, CacheType.GeocoderCache, geo);
716
                                }
717
 
718
                                pointList = new List<PointLatLng>();
719
 
720
                                XmlNodeList l = doc.SelectNodes("//result");
721
                                if (l != null)
722
                                {
723
                                    foreach (XmlNode n in l)
724
                                    {
725
                                        nn = n.SelectSingleNode("geometry/location/lat");
726
                                        if (nn != null)
727
                                        {
728
                                            double lat = double.Parse(nn.InnerText, CultureInfo.InvariantCulture);
729
 
730
                                            nn = n.SelectSingleNode("geometry/location/lng");
731
                                            if (nn != null)
732
                                            {
733
                                                double lng = double.Parse(nn.InnerText, CultureInfo.InvariantCulture);
734
                                                pointList.Add(new PointLatLng(lat, lng));
735
                                            }
736
                                        }
737
                                    }
738
                                }
739
                            }
740
                        }
741
                    }
742
                }
743
            }
744
            catch (Exception ex)
745
            {
746
                status = GeoCoderStatusCode.ExceptionInCode;
747
                Debug.WriteLine("GetLatLngFromGeocoderUrl: " + ex);
748
            }
749
 
750
            return status;
751
        }
752
 
753
        GeoCoderStatusCode GetPlacemarkFromReverseGeocoderUrl(string url, out List<Placemark> placemarkList)
754
        {
755
            GeoCoderStatusCode status = GeoCoderStatusCode.Unknow;
756
            placemarkList = null;
757
 
758
            try
759
            {
760
                string reverse = GMaps.Instance.UsePlacemarkCache ? Cache.Instance.GetContent(url, CacheType.PlacemarkCache) : string.Empty;
761
 
762
                bool cache = false;
763
 
764
                if (string.IsNullOrEmpty(reverse))
765
                {
766
                    string urls = url;
767
 
768
                    // Must provide either API key or Maps for Work credentials.
769
                    if (!string.IsNullOrEmpty(ClientId))
770
                    {
771
                        urls = GetSignedUri(url);
772
                    }
773
                    else if (!string.IsNullOrEmpty(ApiKey))
774
                    {
775
                        urls += "&key=" + ApiKey;
776
                    }
777
 
778
                    reverse = GetContentUsingHttp(urls);
779
 
780
                    if (!string.IsNullOrEmpty(reverse))
781
                    {
782
                        cache = true;
783
                    }
784
                }
785
 
786
                if (!string.IsNullOrEmpty(reverse))
787
                {
788
                    if (reverse.StartsWith("<?xml"))
789
                    {
790
                        #region -- xml response --
791
                        //<?xml version="1.0" encoding="UTF-8"?>
792
                        //<GeocodeResponse>
793
                        // <status>OK</status>
794
                        // <result>
795
                        //  <type>street_address</type>
796
                        //  <formatted_address>Tuskul??n?? gatv?? 2, Vilnius 09213, Lithuania</formatted_address>
797
                        //  <address_component>
798
                        //   <long_name>2</long_name>
799
                        //   <short_name>2</short_name>
800
                        //   <type>street_number</type>
801
                        //  </address_component>
802
                        //  <address_component>
803
                        //   <long_name>Tuskul??n?? gatv??</long_name>
804
                        //   <short_name>Tuskul??n?? g.</short_name>
805
                        //   <type>route</type>
806
                        //  </address_component>
807
                        //  <address_component>
808
                        //   <long_name>Vilnius</long_name>
809
                        //   <short_name>Vilnius</short_name>
810
                        //   <type>locality</type>
811
                        //   <type>political</type>
812
                        //  </address_component>
813
                        //  <address_component>
814
                        //   <long_name>Vilniaus miesto savivaldyb??</long_name>
815
                        //   <short_name>Vilniaus m. sav.</short_name>
816
                        //   <type>administrative_area_level_2</type>
817
                        //   <type>political</type>
818
                        //  </address_component>
819
                        //  <address_component>
820
                        //   <long_name>Vilnius County</long_name>
821
                        //   <short_name>Vilnius County</short_name>
822
                        //   <type>administrative_area_level_1</type>
823
                        //   <type>political</type>
824
                        //  </address_component>
825
                        //  <address_component>
826
                        //   <long_name>Lithuania</long_name>
827
                        //   <short_name>LT</short_name>
828
                        //   <type>country</type>
829
                        //   <type>political</type>
830
                        //  </address_component>
831
                        //  <address_component>
832
                        //   <long_name>09213</long_name>
833
                        //   <short_name>09213</short_name>
834
                        //   <type>postal_code</type>
835
                        //  </address_component>
836
                        //  <geometry>
837
                        //   <location>
838
                        //    <lat>54.6963339</lat>
839
                        //    <lng>25.2968939</lng>
840
                        //   </location>
841
                        //   <location_type>ROOFTOP</location_type>
842
                        //   <viewport>
843
                        //    <southwest>
844
                        //     <lat>54.6949849</lat>
845
                        //     <lng>25.2955449</lng>
846
                        //    </southwest>
847
                        //    <northeast>
848
                        //     <lat>54.6976829</lat>
849
                        //     <lng>25.2982429</lng>
850
                        //    </northeast>
851
                        //   </viewport>
852
                        //  </geometry>
853
                        // </result>
854
                        // <result>
855
                        //  <type>postal_code</type>
856
                        //  <formatted_address>Vilnius 09213, Lithuania</formatted_address>
857
                        //  <address_component>
858
                        //   <long_name>09213</long_name>
859
                        //   <short_name>09213</short_name>
860
                        //   <type>postal_code</type>
861
                        //  </address_component>
862
                        //  <address_component>
863
                        //   <long_name>Vilnius</long_name>
864
                        //   <short_name>Vilnius</short_name>
865
                        //   <type>locality</type>
866
                        //   <type>political</type>
867
                        //  </address_component>
868
                        //  <address_component>
869
                        //   <long_name>Vilniaus miesto savivaldyb??</long_name>
870
                        //   <short_name>Vilniaus m. sav.</short_name>
871
                        //   <type>administrative_area_level_2</type>
872
                        //   <type>political</type>
873
                        //  </address_component>
874
                        //  <address_component>
875
                        //   <long_name>Vilnius County</long_name>
876
                        //   <short_name>Vilnius County</short_name>
877
                        //   <type>administrative_area_level_1</type>
878
                        //   <type>political</type>
879
                        //  </address_component>
880
                        //  <address_component>
881
                        //   <long_name>Lithuania</long_name>
882
                        //   <short_name>LT</short_name>
883
                        //   <type>country</type>
884
                        //   <type>political</type>
885
                        //  </address_component>
886
                        //  <geometry>
887
                        //   <location>
888
                        //    <lat>54.6963032</lat>
889
                        //    <lng>25.2967390</lng>
890
                        //   </location>
891
                        //   <location_type>APPROXIMATE</location_type>
892
                        //   <viewport>
893
                        //    <southwest>
894
                        //     <lat>54.6950889</lat>
895
                        //     <lng>25.2958851</lng>
896
                        //    </southwest>
897
                        //    <northeast>
898
                        //     <lat>54.6977869</lat>
899
                        //     <lng>25.2985830</lng>
900
                        //    </northeast>
901
                        //   </viewport>
902
                        //   <bounds>
903
                        //    <southwest>
904
                        //     <lat>54.6956179</lat>
905
                        //     <lng>25.2958871</lng>
906
                        //    </southwest>
907
                        //    <northeast>
908
                        //     <lat>54.6972579</lat>
909
                        //     <lng>25.2985810</lng>
910
                        //    </northeast>
911
                        //   </bounds>
912
                        //  </geometry>
913
                        // </result>
914
                        // <result>
915
                        //  <type>neighborhood</type>
916
                        //  <type>political</type>
917
                        //  <formatted_address>??irm??nai, Vilnius, Lithuania</formatted_address>
918
                        //  <address_component>
919
                        //   <long_name>??irm??nai</long_name>
920
                        //   <short_name>??irm??nai</short_name>
921
                        //   <type>neighborhood</type>
922
                        //   <type>political</type>
923
                        //  </address_component>
924
                        //  <address_component>
925
                        //   <long_name>Vilnius</long_name>
926
                        //   <short_name>Vilnius</short_name>
927
                        //   <type>locality</type>
928
                        //   <type>political</type>
929
                        //  </address_component>
930
                        //  <address_component>
931
                        //   <long_name>Vilniaus miesto savivaldyb??</long_name>
932
                        //   <short_name>Vilniaus m. sav.</short_name>
933
                        //   <type>administrative_area_level_2</type>
934
                        //   <type>political</type>
935
                        //  </address_component>
936
                        //  <address_component>
937
                        //   <long_name>Vilnius County</long_name>
938
                        //   <short_name>Vilnius County</short_name>
939
                        //   <type>administrative_area_level_1</type>
940
                        //   <type>political</type>
941
                        //  </address_component>
942
                        //  <address_component>
943
                        //   <long_name>Lithuania</long_name>
944
                        //   <short_name>LT</short_name>
945
                        //   <type>country</type>
946
                        //   <type>political</type>
947
                        //  </address_component>
948
                        //  <geometry>
949
                        //   <location>
950
                        //    <lat>54.7117424</lat>
951
                        //    <lng>25.2974345</lng>
952
                        //   </location>
953
                        //   <location_type>APPROXIMATE</location_type>
954
                        //   <viewport>
955
                        //    <southwest>
956
                        //     <lat>54.6888939</lat>
957
                        //     <lng>25.2838700</lng>
958
                        //    </southwest>
959
                        //    <northeast>
960
                        //     <lat>54.7304441</lat>
961
                        //     <lng>25.3133630</lng>
962
                        //    </northeast>
963
                        //   </viewport>
964
                        //   <bounds>
965
                        //    <southwest>
966
                        //     <lat>54.6888939</lat>
967
                        //     <lng>25.2838700</lng>
968
                        //    </southwest>
969
                        //    <northeast>
970
                        //     <lat>54.7304441</lat>
971
                        //     <lng>25.3133630</lng>
972
                        //    </northeast>
973
                        //   </bounds>
974
                        //  </geometry>
975
                        // </result>
976
                        // <result>
977
                        //  <type>administrative_area_level_3</type>
978
                        //  <type>political</type>
979
                        //  <formatted_address>??irm??n?? seni??nija, Lithuania</formatted_address>
980
                        //  <address_component>
981
                        //   <long_name>??irm??n?? seni??nija</long_name>
982
                        //   <short_name>??irm??n?? sen.</short_name>
983
                        //   <type>administrative_area_level_3</type>
984
                        //   <type>political</type>
985
                        //  </address_component>
986
                        //  <address_component>
987
                        //   <long_name>Vilniaus miesto savivaldyb??</long_name>
988
                        //   <short_name>Vilniaus m. sav.</short_name>
989
                        //   <type>administrative_area_level_2</type>
990
                        //   <type>political</type>
991
                        //  </address_component>
992
                        //  <address_component>
993
                        //   <long_name>Vilnius County</long_name>
994
                        //   <short_name>Vilnius County</short_name>
995
                        //   <type>administrative_area_level_1</type>
996
                        //   <type>political</type>
997
                        //  </address_component>
998
                        //  <address_component>
999
                        //   <long_name>Lithuania</long_name>
1000
                        //   <short_name>LT</short_name>
1001
                        //   <type>country</type>
1002
                        //   <type>political</type>
1003
                        //  </address_component>
1004
                        //  <geometry>
1005
                        //   <location>
1006
                        //    <lat>54.7117424</lat>
1007
                        //    <lng>25.2974345</lng>
1008
                        //   </location>
1009
                        //   <location_type>APPROXIMATE</location_type>
1010
                        //   <viewport>
1011
                        //    <southwest>
1012
                        //     <lat>54.6892135</lat>
1013
                        //     <lng>25.2837150</lng>
1014
                        //    </southwest>
1015
                        //    <northeast>
1016
                        //     <lat>54.7305878</lat>
1017
                        //     <lng>25.3135630</lng>
1018
                        //    </northeast>
1019
                        //   </viewport>
1020
                        //   <bounds>
1021
                        //    <southwest>
1022
                        //     <lat>54.6892135</lat>
1023
                        //     <lng>25.2837150</lng>
1024
                        //    </southwest>
1025
                        //    <northeast>
1026
                        //     <lat>54.7305878</lat>
1027
                        //     <lng>25.3135630</lng>
1028
                        //    </northeast>
1029
                        //   </bounds>
1030
                        //  </geometry>
1031
                        // </result>
1032
                        // <result>
1033
                        //  <type>locality</type>
1034
                        //  <type>political</type>
1035
                        //  <formatted_address>Vilnius, Lithuania</formatted_address>
1036
                        //  <address_component>
1037
                        //   <long_name>Vilnius</long_name>
1038
                        //   <short_name>Vilnius</short_name>
1039
                        //   <type>locality</type>
1040
                        //   <type>political</type>
1041
                        //  </address_component>
1042
                        //  <address_component>
1043
                        //   <long_name>Vilniaus miesto savivaldyb??</long_name>
1044
                        //   <short_name>Vilniaus m. sav.</short_name>
1045
                        //   <type>administrative_area_level_2</type>
1046
                        //   <type>political</type>
1047
                        //  </address_component>
1048
                        //  <address_component>
1049
                        //   <long_name>Vilnius County</long_name>
1050
                        //   <short_name>Vilnius County</short_name>
1051
                        //   <type>administrative_area_level_1</type>
1052
                        //   <type>political</type>
1053
                        //  </address_component>
1054
                        //  <address_component>
1055
                        //   <long_name>Lithuania</long_name>
1056
                        //   <short_name>LT</short_name>
1057
                        //   <type>country</type>
1058
                        //   <type>political</type>
1059
                        //  </address_component>
1060
                        //  <geometry>
1061
                        //   <location>
1062
                        //    <lat>54.6871555</lat>
1063
                        //    <lng>25.2796514</lng>
1064
                        //   </location>
1065
                        //   <location_type>APPROXIMATE</location_type>
1066
                        //   <viewport>
1067
                        //    <southwest>
1068
                        //     <lat>54.5677980</lat>
1069
                        //     <lng>25.0243760</lng>
1070
                        //    </southwest>
1071
                        //    <northeast>
1072
                        //     <lat>54.8325440</lat>
1073
                        //     <lng>25.4814883</lng>
1074
                        //    </northeast>
1075
                        //   </viewport>
1076
                        //   <bounds>
1077
                        //    <southwest>
1078
                        //     <lat>54.5677980</lat>
1079
                        //     <lng>25.0243760</lng>
1080
                        //    </southwest>
1081
                        //    <northeast>
1082
                        //     <lat>54.8325440</lat>
1083
                        //     <lng>25.4814883</lng>
1084
                        //    </northeast>
1085
                        //   </bounds>
1086
                        //  </geometry>
1087
                        // </result>
1088
                        // <result>
1089
                        //  <type>administrative_area_level_2</type>
1090
                        //  <type>political</type>
1091
                        //  <formatted_address>Vilniaus miesto savivaldyb??, Lithuania</formatted_address>
1092
                        //  <address_component>
1093
                        //   <long_name>Vilniaus miesto savivaldyb??</long_name>
1094
                        //   <short_name>Vilniaus m. sav.</short_name>
1095
                        //   <type>administrative_area_level_2</type>
1096
                        //   <type>political</type>
1097
                        //  </address_component>
1098
                        //  <address_component>
1099
                        //   <long_name>Vilnius County</long_name>
1100
                        //   <short_name>Vilnius County</short_name>
1101
                        //   <type>administrative_area_level_1</type>
1102
                        //   <type>political</type>
1103
                        //  </address_component>
1104
                        //  <address_component>
1105
                        //   <long_name>Lithuania</long_name>
1106
                        //   <short_name>LT</short_name>
1107
                        //   <type>country</type>
1108
                        //   <type>political</type>
1109
                        //  </address_component>
1110
                        //  <geometry>
1111
                        //   <location>
1112
                        //    <lat>54.6759715</lat>
1113
                        //    <lng>25.2867413</lng>
1114
                        //   </location>
1115
                        //   <location_type>APPROXIMATE</location_type>
1116
                        //   <viewport>
1117
                        //    <southwest>
1118
                        //     <lat>54.5677980</lat>
1119
                        //     <lng>25.0243760</lng>
1120
                        //    </southwest>
1121
                        //    <northeast>
1122
                        //     <lat>54.8325440</lat>
1123
                        //     <lng>25.4814883</lng>
1124
                        //    </northeast>
1125
                        //   </viewport>
1126
                        //   <bounds>
1127
                        //    <southwest>
1128
                        //     <lat>54.5677980</lat>
1129
                        //     <lng>25.0243760</lng>
1130
                        //    </southwest>
1131
                        //    <northeast>
1132
                        //     <lat>54.8325440</lat>
1133
                        //     <lng>25.4814883</lng>
1134
                        //    </northeast>
1135
                        //   </bounds>
1136
                        //  </geometry>
1137
                        // </result>
1138
                        // <result>
1139
                        //  <type>administrative_area_level_1</type>
1140
                        //  <type>political</type>
1141
                        //  <formatted_address>Vilnius County, Lithuania</formatted_address>
1142
                        //  <address_component>
1143
                        //   <long_name>Vilnius County</long_name>
1144
                        //   <short_name>Vilnius County</short_name>
1145
                        //   <type>administrative_area_level_1</type>
1146
                        //   <type>political</type>
1147
                        //  </address_component>
1148
                        //  <address_component>
1149
                        //   <long_name>Lithuania</long_name>
1150
                        //   <short_name>LT</short_name>
1151
                        //   <type>country</type>
1152
                        //   <type>political</type>
1153
                        //  </address_component>
1154
                        //  <geometry>
1155
                        //   <location>
1156
                        //    <lat>54.8086502</lat>
1157
                        //    <lng>25.2182138</lng>
1158
                        //   </location>
1159
                        //   <location_type>APPROXIMATE</location_type>
1160
                        //   <viewport>
1161
                        //    <southwest>
1162
                        //     <lat>54.1276599</lat>
1163
                        //     <lng>24.3863751</lng>
1164
                        //    </southwest>
1165
                        //    <northeast>
1166
                        //     <lat>55.5174369</lat>
1167
                        //     <lng>26.7602130</lng>
1168
                        //    </northeast>
1169
                        //   </viewport>
1170
                        //   <bounds>
1171
                        //    <southwest>
1172
                        //     <lat>54.1276599</lat>
1173
                        //     <lng>24.3863751</lng>
1174
                        //    </southwest>
1175
                        //    <northeast>
1176
                        //     <lat>55.5174369</lat>
1177
                        //     <lng>26.7602130</lng>
1178
                        //    </northeast>
1179
                        //   </bounds>
1180
                        //  </geometry>
1181
                        // </result>
1182
                        // <result>
1183
                        //  <type>country</type>
1184
                        //  <type>political</type>
1185
                        //  <formatted_address>Lithuania</formatted_address>
1186
                        //  <address_component>
1187
                        //   <long_name>Lithuania</long_name>
1188
                        //   <short_name>LT</short_name>
1189
                        //   <type>country</type>
1190
                        //   <type>political</type>
1191
                        //  </address_component>
1192
                        //  <geometry>
1193
                        //   <location>
1194
                        //    <lat>55.1694380</lat>
1195
                        //    <lng>23.8812750</lng>
1196
                        //   </location>
1197
                        //   <location_type>APPROXIMATE</location_type>
1198
                        //   <viewport>
1199
                        //    <southwest>
1200
                        //     <lat>53.8968787</lat>
1201
                        //     <lng>20.9543679</lng>
1202
                        //    </southwest>
1203
                        //    <northeast>
1204
                        //     <lat>56.4503209</lat>
1205
                        //     <lng>26.8355913</lng>
1206
                        //    </northeast>
1207
                        //   </viewport>
1208
                        //   <bounds>
1209
                        //    <southwest>
1210
                        //     <lat>53.8968787</lat>
1211
                        //     <lng>20.9543679</lng>
1212
                        //    </southwest>
1213
                        //    <northeast>
1214
                        //     <lat>56.4503209</lat>
1215
                        //     <lng>26.8355913</lng>
1216
                        //    </northeast>
1217
                        //   </bounds>
1218
                        //  </geometry>
1219
                        // </result>
1220
                        //</GeocodeResponse>
1221
 
1222
                        #endregion
1223
 
1224
                        XmlDocument doc = new XmlDocument();
1225
                        doc.LoadXml(reverse);
1226
 
1227
                        XmlNode nn = doc.SelectSingleNode("//status");
1228
                        if (nn != null)
1229
                        {
1230
                            if (nn.InnerText != "OK")
1231
                            {
1232
                                Debug.WriteLine("GetPlacemarkFromReverseGeocoderUrl: " + nn.InnerText);
1233
                            }
1234
                            else
1235
                            {
1236
                                status = GeoCoderStatusCode.G_GEO_SUCCESS;
1237
 
1238
                                if (cache && GMaps.Instance.UsePlacemarkCache)
1239
                                {
1240
                                    Cache.Instance.SaveContent(url, CacheType.PlacemarkCache, reverse);
1241
                                }
1242
 
1243
                                placemarkList = new List<Placemark>();
1244
 
1245
                                #region -- placemarks --
1246
                                XmlNodeList l = doc.SelectNodes("//result");
1247
                                if (l != null)
1248
                                {
1249
                                    foreach (XmlNode n in l)
1250
                                    {
1251
                                        Debug.WriteLine("---------------------");
1252
 
1253
                                        nn = n.SelectSingleNode("formatted_address");
1254
                                        if (nn != null)
1255
                                        {
1256
                                            var ret = new Placemark(nn.InnerText);
1257
 
1258
                                            Debug.WriteLine("formatted_address: [" + nn.InnerText + "]");
1259
 
1260
                                            nn = n.SelectSingleNode("type");
1261
                                            if (nn != null)
1262
                                            {
1263
                                                Debug.WriteLine("type: " + nn.InnerText);
1264
                                            }
1265
 
1266
                                            // TODO: fill Placemark details
1267
 
1268
                                            XmlNodeList acl = n.SelectNodes("address_component");
1269
                                            foreach (XmlNode ac in acl)
1270
                                            {
1271
                                                nn = ac.SelectSingleNode("type");
1272
                                                if (nn != null)
1273
                                                {
1274
                                                    var type = nn.InnerText;
1275
                                                    Debug.Write(" - [" + type + "], ");
1276
 
1277
                                                    nn = ac.SelectSingleNode("long_name");
1278
                                                    if (nn != null)
1279
                                                    {
1280
                                                        Debug.WriteLine("long_name: [" + nn.InnerText + "]");
1281
 
1282
                                                        switch (type)
1283
                                                        {
1284
                                                            case "street_address":
1285
                                                            {
1286
                                                                ret.StreetNumber = nn.InnerText;
1287
                                                            }
1288
                                                            break;
1289
 
1290
                                                            case "route":
1291
                                                            {
1292
                                                                ret.ThoroughfareName = nn.InnerText;
1293
                                                            }
1294
                                                            break;
1295
 
1296
                                                            case "postal_code":
1297
                                                            {
1298
                                                                ret.PostalCodeNumber = nn.InnerText;
1299
                                                            }
1300
                                                            break;
1301
 
1302
                                                            case "country":
1303
                                                            {
1304
                                                                ret.CountryName = nn.InnerText;
1305
                                                            }
1306
                                                            break;
1307
 
1308
                                                            case "locality":
1309
                                                            {
1310
                                                                ret.LocalityName = nn.InnerText;
1311
                                                            }
1312
                                                            break;
1313
 
1314
                                                            case "administrative_area_level_2":
1315
                                                            {
1316
                                                              ret.DistrictName = nn.InnerText;
1317
                                                            }
1318
                                                            break;
1319
 
1320
                                                            case "administrative_area_level_1":
1321
                                                            {
1322
                                                                ret.AdministrativeAreaName = nn.InnerText;
1323
                                                            }
1324
                                                            break;
1325
 
1326
                                                            case "administrative_area_level_3":
1327
                                                            {
1328
                                                                ret.SubAdministrativeAreaName = nn.InnerText;
1329
                                                            }
1330
                                                            break;
1331
 
1332
                                                            case "neighborhood":
1333
                                                            {
1334
                                                                ret.Neighborhood = nn.InnerText;
1335
                                                            }
1336
                                                            break;
1337
                                                        }
1338
                                                    }
1339
                                                }
1340
                                            }                                            
1341
 
1342
                                            placemarkList.Add(ret);
1343
                                        }
1344
                                    }
1345
                                }
1346
                                #endregion
1347
                            }
1348
                        }
1349
        #endregion
1350
                    }
1351
                }
1352
            }
1353
            catch (Exception ex)
1354
            {
1355
                status = GeoCoderStatusCode.ExceptionInCode;
1356
                placemarkList = null;
1357
                Debug.WriteLine("GetPlacemarkReverseGeocoderUrl: " + ex.ToString());
1358
            }
1359
 
1360
            return status;
1361
        }
1362
 
1363
        static readonly string ReverseGeocoderUrlFormat = "http://maps.{0}/maps/api/geocode/xml?latlng={1},{2}&language={3}&sensor=false";
1364
        static readonly string GeocoderUrlFormat = "http://maps.{0}/maps/api/geocode/xml?address={1}&language={2}&sensor=false";
1365
 
1366
        #endregion
1367
 
1368
        #region DirectionsProvider Members
1369
 
1370
        public DirectionsStatusCode GetDirections(out GDirections direction, PointLatLng start, PointLatLng end, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
1371
        {
1372
            return GetDirectionsUrl(MakeDirectionsUrl(start, end, LanguageStr, avoidHighways, avoidTolls, walkingMode, sensor, metric), out direction);
1373
        }
1374
 
1375
        public DirectionsStatusCode GetDirections(out GDirections direction, string start, string end, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
1376
        {
1377
            return GetDirectionsUrl(MakeDirectionsUrl(start, end, LanguageStr, avoidHighways, avoidTolls, walkingMode, sensor, metric), out direction);
1378
        }
1379
 
1380
        /// <summary>
1381
        /// NotImplemented
1382
        /// </summary>
1383
        /// <param name="status"></param>
1384
        /// <param name="start"></param>
1385
        /// <param name="end"></param>
1386
        /// <param name="avoidHighways"></param>
1387
        /// <param name="avoidTolls"></param>
1388
        /// <param name="walkingMode"></param>
1389
        /// <param name="sensor"></param>
1390
        /// <param name="metric"></param>
1391
        /// <returns></returns>
1392
        public IEnumerable<GDirections> GetDirections(out DirectionsStatusCode status, string start, string end, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
1393
        {
1394
            // TODO: add alternative directions
1395
 
1396
            throw new NotImplementedException();
1397
        }
1398
 
1399
        /// <summary>
1400
        /// NotImplemented
1401
        /// </summary>
1402
        /// <param name="status"></param>
1403
        /// <param name="start"></param>
1404
        /// <param name="end"></param>
1405
        /// <param name="avoidHighways"></param>
1406
        /// <param name="avoidTolls"></param>
1407
        /// <param name="walkingMode"></param>
1408
        /// <param name="sensor"></param>
1409
        /// <param name="metric"></param>
1410
        /// <returns></returns>
1411
        public IEnumerable<GDirections> GetDirections(out DirectionsStatusCode status, PointLatLng start, PointLatLng end, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
1412
        {
1413
            // TODO: add alternative directions
1414
 
1415
            throw new NotImplementedException();
1416
        }
1417
 
1418
        public DirectionsStatusCode GetDirections(out GDirections direction, PointLatLng start, IEnumerable<PointLatLng> wayPoints, PointLatLng end, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
1419
        {
1420
            return GetDirectionsUrl(MakeDirectionsUrl(start, wayPoints, end, LanguageStr, avoidHighways, avoidTolls, walkingMode, sensor, metric), out direction);
1421
        }
1422
 
1423
        public DirectionsStatusCode GetDirections(out GDirections direction, string start, IEnumerable<string> wayPoints, string end, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
1424
        {
1425
            return GetDirectionsUrl(MakeDirectionsUrl(start, wayPoints, end, LanguageStr, avoidHighways, avoidTolls, walkingMode, sensor, metric), out direction);
1426
        }
1427
 
1428
        #region -- internals --
1429
 
1430
        // The Coogle Directions API: http://tinyurl.com/6vv4cac
1431
 
1432
        string MakeDirectionsUrl(PointLatLng start, PointLatLng end, string language, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
1433
        {
1434
            string av = (avoidHighways ? "&avoid=highways" : string.Empty) + (avoidTolls ? "&avoid=tolls" : string.Empty); // 6
1435
            string mt = "&units=" + (metric ? "metric" : "imperial");     // 7
1436
            string wk = "&mode=" + (walkingMode ? "walking" : "driving"); // 8
1437
 
1438
            return string.Format(CultureInfo.InvariantCulture, DirectionUrlFormatPoint, start.Lat, start.Lng, end.Lat, end.Lng, sensor.ToString().ToLower(), language, av, mt, wk, ServerAPIs);
1439
        }
1440
 
1441
        string MakeDirectionsUrl(string start, string end, string language, bool avoidHighways, bool walkingMode, bool avoidTolls, bool sensor, bool metric)
1442
        {
1443
            string av = (avoidHighways ? "&avoid=highways" : string.Empty) + (avoidTolls ? "&avoid=tolls" : string.Empty); // 4
1444
            string mt = "&units=" + (metric ? "metric" : "imperial");     // 5
1445
            string wk = "&mode=" + (walkingMode ? "walking" : "driving"); // 6
1446
 
1447
            return string.Format(DirectionUrlFormatStr, start.Replace(' ', '+'), end.Replace(' ', '+'), sensor.ToString().ToLower(), language, av, mt, wk, ServerAPIs);
1448
        }
1449
 
1450
        string MakeDirectionsUrl(PointLatLng start, IEnumerable<PointLatLng> wayPoints, PointLatLng end, string language, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
1451
        {
1452
            string av = (avoidHighways ? "&avoid=highways" : string.Empty) + (avoidTolls ? "&avoid=tolls" : string.Empty); // 6
1453
            string mt = "&units=" + (metric ? "metric" : "imperial"); // 7
1454
            string wk = "&mode=" + (walkingMode ? "walking" : "driving"); // 8
1455
 
1456
            string wpLatLng = string.Empty;
1457
            int i = 0;
1458
            foreach (var wp in wayPoints)
1459
            {
1460
                wpLatLng += string.Format(CultureInfo.InvariantCulture, i++ == 0 ? "{0},{1}" : "|{0},{1}", wp.Lat, wp.Lng);
1461
            }
1462
 
1463
            return string.Format(CultureInfo.InvariantCulture, DirectionUrlFormatWaypoint, start.Lat, start.Lng, wpLatLng, sensor.ToString().ToLower(), language, av, mt, wk, ServerAPIs, end.Lat, end.Lng);
1464
        }
1465
 
1466
        string MakeDirectionsUrl(string start, IEnumerable<string> wayPoints, string end, string language, bool avoidHighways, bool avoidTolls, bool walkingMode, bool sensor, bool metric)
1467
        {
1468
            string av = (avoidHighways ? "&avoid=highways" : string.Empty) + (avoidTolls ? "&avoid=tolls" : string.Empty); // 6
1469
            string mt = "&units=" + (metric ? "metric" : "imperial"); // 7
1470
            string wk = "&mode=" + (walkingMode ? "walking" : "driving"); // 8
1471
 
1472
            string wpLatLng = string.Empty;
1473
            int i = 0;
1474
            foreach (var wp in wayPoints)
1475
            {
1476
                wpLatLng += string.Format(CultureInfo.InvariantCulture, i++ == 0 ? "{0}" : "|{0}", wp.Replace(' ', '+'));
1477
            }
1478
 
1479
            return string.Format(CultureInfo.InvariantCulture, DirectionUrlFormatWaypointStr, start.Replace(' ', '+'), wpLatLng, sensor.ToString().ToLower(), language, av, mt, wk, ServerAPIs, end.Replace(' ', '+'));
1480
        }
1481
 
1482
        DirectionsStatusCode GetDirectionsUrl(string url, out GDirections direction)
1483
        {
1484
            DirectionsStatusCode ret = DirectionsStatusCode.UNKNOWN_ERROR;
1485
            direction = null;
1486
 
1487
            try
1488
            {
1489
                string kml = GMaps.Instance.UseDirectionsCache ? Cache.Instance.GetContent(url, CacheType.DirectionsCache) : string.Empty;
1490
 
1491
                bool cache = false;
1492
 
1493
                if (string.IsNullOrEmpty(kml))
1494
                {
1495
                    string urls = url;
1496
 
1497
                    // Must provide either API key or Maps for Work credentials.
1498
                    if (!string.IsNullOrEmpty(ClientId))
1499
                    {
1500
                        urls = GetSignedUri(url);
1501
                    }
1502
                    else if (!string.IsNullOrEmpty(ApiKey))
1503
                    {
1504
                        urls += "&key=" + ApiKey;
1505
                    }
1506
 
1507
                    kml = GetContentUsingHttp(urls);
1508
 
1509
                    if (!string.IsNullOrEmpty(kml))
1510
                    {
1511
                        cache = true;
1512
                    }
1513
                }
1514
 
1515
                if (!string.IsNullOrEmpty(kml))
1516
                {
1517
                    #region -- kml response --
1518
                    //<?xml version="1.0" encoding="UTF-8"?>
1519
                    //<DirectionsResponse>
1520
                    // <status>OK</status>
1521
                    // <route>
1522
                    //  <summary>A1/E85</summary>
1523
                    //  <leg>
1524
                    //   <step>
1525
                    //    <travel_mode>DRIVING</travel_mode>
1526
                    //    <start_location>
1527
                    //     <lat>54.6893800</lat>
1528
                    //     <lng>25.2800500</lng>
1529
                    //    </start_location>
1530
                    //    <end_location>
1531
                    //     <lat>54.6907800</lat>
1532
                    //     <lng>25.2798000</lng>
1533
                    //    </end_location>
1534
                    //    <polyline>
1535
                    //     <points>soxlIiohyCYLkCJ}@Vs@?</points>
1536
                    //    </polyline>
1537
                    //    <duration>
1538
                    //     <value>32</value>
1539
                    //     <text>1 min</text>
1540
                    //    </duration>
1541
                    //    <html_instructions>Head &lt;b&gt;north&lt;/b&gt; on &lt;b&gt;Vilniaus gatvė&lt;/b&gt; toward &lt;b&gt;Tilto gatvė&lt;/b&gt;</html_instructions>
1542
                    //    <distance>
1543
                    //     <value>157</value>
1544
                    //     <text>0.2 km</text>
1545
                    //    </distance>
1546
                    //   </step>
1547
                    //   <step>
1548
                    //    <travel_mode>DRIVING</travel_mode>
1549
                    //    <start_location>
1550
                    //     <lat>54.6907800</lat>
1551
                    //     <lng>25.2798000</lng>
1552
                    //    </start_location>
1553
                    //    <end_location>
1554
                    //     <lat>54.6942500</lat>
1555
                    //     <lng>25.2621300</lng>
1556
                    //    </end_location>
1557
                    //    <polyline>
1558
                    //     <points>kxxlIwmhyCmApUF`@GvAYpD{@dGcCjIoIvOuAhDwAtEa@vBUnDAhB?~AThDRxAh@hBtAdC</points>
1559
                    //    </polyline>
1560
                    //    <duration>
1561
                    //     <value>133</value>
1562
                    //     <text>2 mins</text>
1563
                    //    </duration>
1564
                    //    <html_instructions>Turn &lt;b&gt;left&lt;/b&gt; onto &lt;b&gt;A. Goštauto gatvė&lt;/b&gt;</html_instructions>
1565
                    //    <distance>
1566
                    //     <value>1326</value>
1567
                    //     <text>1.3 km</text>
1568
                    //    </distance>
1569
                    //   </step>
1570
                    //   <step>
1571
                    //    <travel_mode>DRIVING</travel_mode>
1572
                    //    <start_location>
1573
                    //     <lat>54.6942500</lat>
1574
                    //     <lng>25.2621300</lng>
1575
                    //    </start_location>
1576
                    //    <end_location>
1577
                    //     <lat>54.6681200</lat>
1578
                    //     <lng>25.2377500</lng>
1579
                    //    </end_location>
1580
                    //    <polyline>
1581
                    //     <points>anylIi_eyC`AwD~@oBLKr@K`U|FdF|@`J^~E[j@Lh@\hB~Bn@tBZhBLrC?zIJ~DzA~OVrELlG^lDdAtDh@hAfApA`EzCvAp@jUpIpAl@bBpAdBpBxA|BdLpV`BxClAbBhBlBbChBpBhAdAXjBHlE_@t@?|@Lt@X</points>
1582
                    //    </polyline>
1583
                    //    <duration>
1584
                    //     <value>277</value>
1585
                    //     <text>5 mins</text>
1586
                    //    </duration>
1587
                    //    <html_instructions>Turn &lt;b&gt;left&lt;/b&gt; to merge onto &lt;b&gt;Geležinio Vilko gatvė&lt;/b&gt;</html_instructions>
1588
                    //    <distance>
1589
                    //     <value>3806</value>
1590
                    //     <text>3.8 km</text>
1591
                    //    </distance>
1592
                    //   </step>
1593
                    //   <step>
1594
                    //    <travel_mode>DRIVING</travel_mode>
1595
                    //    <start_location>
1596
                    //     <lat>54.6681200</lat>
1597
                    //     <lng>25.2377500</lng>
1598
                    //    </start_location>
1599
                    //    <end_location>
1600
                    //     <lat>54.6584100</lat>
1601
                    //     <lng>25.1411300</lng>
1602
                    //    </end_location>
1603
                    //    <polyline>
1604
                    //     <points>wjtlI}f`yC~FhBlFr@jD|A~EbC~VjNxBbBdA`BnvA|zCba@l`Bt@tDTbBJpBBfBMvDaAzF}bBjiF{HnXiHxZ</points>
1605
                    //    </polyline>
1606
                    //    <duration>
1607
                    //     <value>539</value>
1608
                    //     <text>9 mins</text>
1609
                    //    </duration>
1610
                    //    <html_instructions>Continue onto &lt;b&gt;Savanorių prospektas&lt;/b&gt;</html_instructions>
1611
                    //    <distance>
1612
                    //     <value>8465</value>
1613
                    //     <text>8.5 km</text>
1614
                    //    </distance>
1615
                    //   </step>
1616
                    //   <step>
1617
                    //    <travel_mode>DRIVING</travel_mode>
1618
                    //    <start_location>
1619
                    //     <lat>54.6584100</lat>
1620
                    //     <lng>25.1411300</lng>
1621
                    //    </start_location>
1622
                    //    <end_location>
1623
                    //     <lat>54.9358200</lat>
1624
                    //     <lng>23.9260000</lng>
1625
                    //    </end_location>
1626
                    //    <polyline>
1627
                    //     <points>anrlIakmxCiq@|qCuBbLcK~n@wUrkAcPnw@gCnPoQt}AoB`MuAdHmAdFoCtJqClImBxE{DrIkQ|ZcEvIkDzIcDhKyBxJ{EdXuCtS_G`g@mF|\eF`WyDhOiE~NiErMaGpOoj@ppAoE|K_EzKeDtKkEnOsLnd@mDzLgI~U{FrNsEvJoEtI_FpI{J`O_EjFooBf_C{GdJ_FjIsH`OoFhMwH`UcDtL{CzMeDlQmAzHuU~bBiArIwApNaBfWaLfiCoBpYsDf\qChR_FlVqEpQ_ZbfA}CfN{A~HwCtRiAfKmBlVwBx[gBfRcBxMaLdp@sXrzAaE~UqCzRyC`[_q@z|LgC|e@m@vNqp@b}WuLraFo@jPaS~bDmJryAeo@v|G}CnWsm@~`EoKvo@kv@lkEkqBrlKwBvLkNj|@cu@`~EgCnNuiBpcJakAx|GyB`KqdC~fKoIfYicAxtCiDrLu@hDyBjQm@xKoGdxBmQhoGuUn|Dc@nJ[`OW|VaEn|Ee@`X</points>
1628
                    //    </polyline>
1629
                    //    <duration>
1630
                    //     <value>3506</value>
1631
                    //     <text>58 mins</text>
1632
                    //    </duration>
1633
                    //    <html_instructions>Continue onto &lt;b&gt;A1/E85&lt;/b&gt;</html_instructions>
1634
                    //    <distance>
1635
                    //     <value>85824</value>
1636
                    //     <text>85.8 km</text>
1637
                    //    </distance>
1638
                    //   </step>
1639
                    //   <step>
1640
                    //    <travel_mode>DRIVING</travel_mode>
1641
                    //    <start_location>
1642
                    //     <lat>54.9358200</lat>
1643
                    //     <lng>23.9260000</lng>
1644
                    //    </start_location>
1645
                    //    <end_location>
1646
                    //     <lat>54.9376500</lat>
1647
                    //     <lng>23.9195600</lng>
1648
                    //    </end_location>
1649
                    //    <polyline>
1650
                    //     <points>{shnIo``qCQ^MnD[lBgA`DqBdEu@xB}@zJCjB</points>
1651
                    //    </polyline>
1652
                    //    <duration>
1653
                    //     <value>39</value>
1654
                    //     <text>1 min</text>
1655
                    //    </duration>
1656
                    //    <html_instructions>Take the exit toward &lt;b&gt;Senamiestis/Aleksotas&lt;/b&gt;</html_instructions>
1657
                    //    <distance>
1658
                    //     <value>476</value>
1659
                    //     <text>0.5 km</text>
1660
                    //    </distance>
1661
                    //   </step>
1662
                    //   <step>
1663
                    //    <travel_mode>DRIVING</travel_mode>
1664
                    //    <start_location>
1665
                    //     <lat>54.9376500</lat>
1666
                    //     <lng>23.9195600</lng>
1667
                    //    </start_location>
1668
                    //    <end_location>
1669
                    //     <lat>54.9361300</lat>
1670
                    //     <lng>23.9189700</lng>
1671
                    //    </end_location>
1672
                    //    <polyline>
1673
                    //     <points>i_inIgx~pCnHtB</points>
1674
                    //    </polyline>
1675
                    //    <duration>
1676
                    //     <value>28</value>
1677
                    //     <text>1 min</text>
1678
                    //    </duration>
1679
                    //    <html_instructions>Turn &lt;b&gt;left&lt;/b&gt; onto &lt;b&gt;Kleboniškio gatvė&lt;/b&gt;</html_instructions>
1680
                    //    <distance>
1681
                    //     <value>173</value>
1682
                    //     <text>0.2 km</text>
1683
                    //    </distance>
1684
                    //   </step>
1685
                    //   <step>
1686
                    //    <travel_mode>DRIVING</travel_mode>
1687
                    //    <start_location>
1688
                    //     <lat>54.9361300</lat>
1689
                    //     <lng>23.9189700</lng>
1690
                    //    </start_location>
1691
                    //    <end_location>
1692
                    //     <lat>54.9018900</lat>
1693
                    //     <lng>23.8937000</lng>
1694
                    //    </end_location>
1695
                    //    <polyline>
1696
                    //     <points>yuhnIqt~pCvAb@JLrOvExSdHvDdAv`@pIpHnAdl@hLdB`@nDvAtEjDdCvCjLzOvAzBhC`GpHfRbQd^`JpMPt@ClA</points>
1697
                    //    </polyline>
1698
                    //    <duration>
1699
                    //     <value>412</value>
1700
                    //     <text>7 mins</text>
1701
                    //    </duration>
1702
                    //    <html_instructions>Continue onto &lt;b&gt;Jonavos gatvė&lt;/b&gt;</html_instructions>
1703
                    //    <distance>
1704
                    //     <value>4302</value>
1705
                    //     <text>4.3 km</text>
1706
                    //    </distance>
1707
                    //   </step>
1708
                    //   <step>
1709
                    //    <travel_mode>DRIVING</travel_mode>
1710
                    //    <start_location>
1711
                    //     <lat>54.9018900</lat>
1712
                    //     <lng>23.8937000</lng>
1713
                    //    </start_location>
1714
                    //    <end_location>
1715
                    //     <lat>54.8985600</lat>
1716
                    //     <lng>23.8933400</lng>
1717
                    //    </end_location>
1718
                    //    <polyline>
1719
                    //     <points>y_bnIsvypCMf@FnARlAf@zAl@^v@EZ_@pAe@x@k@xBPpA@pAQNSf@oB</points>
1720
                    //    </polyline>
1721
                    //    <duration>
1722
                    //     <value>69</value>
1723
                    //     <text>1 min</text>
1724
                    //    </duration>
1725
                    //    <html_instructions>At the roundabout, take the &lt;b&gt;3rd&lt;/b&gt; exit and stay on &lt;b&gt;Jonavos gatvė&lt;/b&gt;</html_instructions>
1726
                    //    <distance>
1727
                    //     <value>478</value>
1728
                    //     <text>0.5 km</text>
1729
                    //    </distance>
1730
                    //   </step>
1731
                    //   <step>   
1732
                    //    <travel_mode>DRIVING</travel_mode>
1733
                    //    <start_location>
1734
                    //     <lat>54.8985600</lat>
1735
                    //     <lng>23.8933400</lng>
1736
                    //    </start_location>
1737
                    //    <end_location>
1738
                    //     <lat>54.8968500</lat>
1739
                    //     <lng>23.8930000</lng>
1740
                    //    </end_location>
1741
                    //    <polyline>
1742
                    //     <points>_kanIktypCbEx@pCH</points>
1743
                    //    </polyline>
1744
                    //    <duration>
1745
                    //     <value>38</value>
1746
                    //     <text>1 min</text>
1747
                    //    </duration>
1748
                    //    <html_instructions>Turn &lt;b&gt;right&lt;/b&gt; onto &lt;b&gt;A. Mapu gatvė&lt;/b&gt;&lt;div style=&quot;font-size:0.9em&quot;&gt;Destination will be on the right&lt;/div&gt;</html_instructions>
1749
                    //    <distance>
1750
                    //     <value>192</value>
1751
                    //     <text>0.2 km</text>
1752
                    //    </distance>
1753
                    //   </step>
1754
                    //   <duration>
1755
                    //    <value>5073</value>
1756
                    //    <text>1 hour 25 mins</text>
1757
                    //   </duration>
1758
                    //   <distance>
1759
                    //    <value>105199</value>
1760
                    //    <text>105 km</text>
1761
                    //   </distance>
1762
                    //   <start_location>
1763
                    //    <lat>54.6893800</lat>
1764
                    //    <lng>25.2800500</lng>
1765
                    //   </start_location>
1766
                    //   <end_location>
1767
                    //    <lat>54.8968500</lat>
1768
                    //    <lng>23.8930000</lng>
1769
                    //   </end_location>
1770
                    //   <start_address>Vilnius, Lithuania</start_address>
1771
                    //   <end_address>Kaunas, Lithuania</end_address>
1772
                    //  </leg>
1773
                    //  <copyrights>Map data ©2011 Tele Atlas</copyrights>
1774
                    //  <overview_polyline>
1775
                    //   <points>soxlIiohyCYL}Fb@mApUF`@GvAYpD{@dGcCjIoIvOwBpFy@xC]jBSxCC~E^~Er@lCtAdC`AwD~@oB`AW`U|FdF|@`J^~E[tAj@hB~BjA~ELrCJzOzA~Od@`N^lDdAtDt@xAjAnApDlCbXbKpAl@bBpAdBpBxA|BdLpV`BxCvDpEbChBpBhAdAXjBHbG_@|@LtHbClFr@jK`F~VjNxBbB`@h@rwAt|Cba@l`BjAxGNxEMvDaAzF}bBjiFcFbQ_y@|gD{CxMeBnJcK~n@wh@dkCkAlIoQt}AeEfV}EzQqClImBxE{DrIkQ|ZcEvIkDzIcDhKyBxJ{EdXuCtS_G`g@mF|\eF`WyDhOiE~NiErMaGpOoj@ppAoE|K_EzKeDtKmXzbAgI~U{FrNsEvJoLfT{J`O_EjFooBf_C{GdJkLtSwI`SyClI}CrJcDtL{CzMeDlQcXzlBiArIwApNaBfWaLfiCoBpYsDf\qChR_FlVqEpQ_ZbfAyFfXwCtRiAfKeFfs@gBfRcBxMaLdp@sXrzAaE~UqCzRyC`[_q@z|LuDtu@qp@b}WuLraFo@jPo^r}Faq@pfHaBtMsm@~`EoKvo@kv@lkEcuBjzKkNj|@cu@`~EgCnNuiBpcJakAx|GyB`KqdC~fKoIfYidAbwCoD|MeAbHcA|Im@xK}YnhKyV~gEs@~f@aEn|Ee@`XQ^MnD[lBoF`N}@zJCjBfKxCJLdj@bQv`@pIpHnAdl@hLdB`@nDvAtEjDdCvCbOvSzLhZbQd^`JpMPt@QtBFnAz@hDl@^j@?f@e@pAe@x@k@xBPfCEf@Uj@wBbEx@pCH</points>
1776
                    //  </overview_polyline>
1777
                    //  <bounds>
1778
                    //   <southwest>
1779
                    //    <lat>54.6389500</lat>
1780
                    //    <lng>23.8920900</lng>
1781
                    //   </southwest>
1782
                    //   <northeast>
1783
                    //    <lat>54.9376500</lat>
1784
                    //    <lng>25.2800500</lng>
1785
                    //   </northeast>
1786
                    //  </bounds>
1787
                    // </route>
1788
                    //</DirectionsResponse> 
1789
                    #endregion
1790
 
1791
                    XmlDocument doc = new XmlDocument();
1792
                    doc.LoadXml(kml);
1793
 
1794
                    XmlNode nn = doc.SelectSingleNode("/DirectionsResponse/status");
1795
                    if (nn != null)
1796
                    {
1797
                        ret = (DirectionsStatusCode)Enum.Parse(typeof(DirectionsStatusCode), nn.InnerText, false);
1798
                        if (ret == DirectionsStatusCode.OK)
1799
                        {
1800
                            if (cache && GMaps.Instance.UseDirectionsCache)
1801
                            {
1802
                                Cache.Instance.SaveContent(url, CacheType.DirectionsCache, kml);
1803
                            }
1804
 
1805
                            direction = new GDirections();
1806
 
1807
                            nn = doc.SelectSingleNode("/DirectionsResponse/route/summary");
1808
                            if (nn != null)
1809
                            {
1810
                                direction.Summary = nn.InnerText;
1811
                                Debug.WriteLine("summary: " + direction.Summary);
1812
                            }
1813
 
1814
                            nn = doc.SelectSingleNode("/DirectionsResponse/route/leg/duration");
1815
                            if (nn != null)
1816
                            {
1817
                                var t = nn.SelectSingleNode("text");
1818
                                if (t != null)
1819
                                {
1820
                                    direction.Duration = t.InnerText;
1821
                                    Debug.WriteLine("duration: " + direction.Duration);
1822
                                }
1823
 
1824
                                t = nn.SelectSingleNode("value");
1825
                                if (t != null)
1826
                                {
1827
                                    if (!string.IsNullOrEmpty(t.InnerText))
1828
                                    {
1829
                                        direction.DurationValue = uint.Parse(t.InnerText);
1830
                                        Debug.WriteLine("value: " + direction.DurationValue);
1831
                                    }
1832
                                }
1833
                            }
1834
 
1835
                            nn = doc.SelectSingleNode("/DirectionsResponse/route/leg/distance");
1836
                            if (nn != null)
1837
                            {
1838
                                var t = nn.SelectSingleNode("text");
1839
                                if (t != null)
1840
                                {
1841
                                    direction.Distance = t.InnerText;
1842
                                    Debug.WriteLine("distance: " + direction.Distance);
1843
                                }
1844
 
1845
                                t = nn.SelectSingleNode("value");
1846
                                if (t != null)
1847
                                {
1848
                                    if (!string.IsNullOrEmpty(t.InnerText))
1849
                                    {
1850
                                        direction.DistanceValue = uint.Parse(t.InnerText);
1851
                                        Debug.WriteLine("value: " + direction.DistanceValue);
1852
                                    }
1853
                                }
1854
                            }
1855
 
1856
                            nn = doc.SelectSingleNode("/DirectionsResponse/route/leg/start_location");
1857
                            if (nn != null)
1858
                            {
1859
                                var pt = nn.SelectSingleNode("lat");
1860
                                if (pt != null)
1861
                                {
1862
                                    direction.StartLocation.Lat = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
1863
                                }
1864
 
1865
                                pt = nn.SelectSingleNode("lng");
1866
                                if (pt != null)
1867
                                {
1868
                                    direction.StartLocation.Lng = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
1869
                                }
1870
                            }
1871
 
1872
                            nn = doc.SelectSingleNode("/DirectionsResponse/route/leg/end_location");
1873
                            if (nn != null)
1874
                            {
1875
                                var pt = nn.SelectSingleNode("lat");
1876
                                if (pt != null)
1877
                                {
1878
                                    direction.EndLocation.Lat = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
1879
                                }
1880
 
1881
                                pt = nn.SelectSingleNode("lng");
1882
                                if (pt != null)
1883
                                {
1884
                                    direction.EndLocation.Lng = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
1885
                                }
1886
                            }
1887
 
1888
                            nn = doc.SelectSingleNode("/DirectionsResponse/route/leg/start_address");
1889
                            if (nn != null)
1890
                            {
1891
                                direction.StartAddress = nn.InnerText;
1892
                                Debug.WriteLine("start_address: " + direction.StartAddress);
1893
                            }
1894
 
1895
                            nn = doc.SelectSingleNode("/DirectionsResponse/route/leg/end_address");
1896
                            if (nn != null)
1897
                            {
1898
                                direction.EndAddress = nn.InnerText;
1899
                                Debug.WriteLine("end_address: " + direction.EndAddress);
1900
                            }
1901
 
1902
                            nn = doc.SelectSingleNode("/DirectionsResponse/route/copyrights");
1903
                            if (nn != null)
1904
                            {
1905
                                direction.Copyrights = nn.InnerText;
1906
                                Debug.WriteLine("copyrights: " + direction.Copyrights);
1907
                            }
1908
 
1909
                            nn = doc.SelectSingleNode("/DirectionsResponse/route/overview_polyline/points");
1910
                            if (nn != null)
1911
                            {
1912
                                direction.Route = new List<PointLatLng>();
1913
                                DecodePointsInto(direction.Route, nn.InnerText);
1914
                            }
1915
 
1916
                            XmlNodeList steps = doc.SelectNodes("/DirectionsResponse/route/leg/step");
1917
                            if (steps != null)
1918
                            {
1919
                                if (steps.Count > 0)
1920
                                {
1921
                                    direction.Steps = new List<GDirectionStep>();
1922
                                }
1923
 
1924
                                foreach (XmlNode s in steps)
1925
                                {
1926
                                    GDirectionStep step = new GDirectionStep();
1927
 
1928
                                    Debug.WriteLine("----------------------");
1929
                                    nn = s.SelectSingleNode("travel_mode");
1930
                                    if (nn != null)
1931
                                    {
1932
                                        step.TravelMode = nn.InnerText;
1933
                                        Debug.WriteLine("travel_mode: " + step.TravelMode);
1934
                                    }
1935
 
1936
                                    nn = s.SelectSingleNode("start_location");
1937
                                    if (nn != null)
1938
                                    {
1939
                                        var pt = nn.SelectSingleNode("lat");
1940
                                        if (pt != null)
1941
                                        {
1942
                                            step.StartLocation.Lat = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
1943
                                        }
1944
 
1945
                                        pt = nn.SelectSingleNode("lng");
1946
                                        if (pt != null)
1947
                                        {
1948
                                            step.StartLocation.Lng = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
1949
                                        }
1950
                                    }
1951
 
1952
                                    nn = s.SelectSingleNode("end_location");
1953
                                    if (nn != null)
1954
                                    {
1955
                                        var pt = nn.SelectSingleNode("lat");
1956
                                        if (pt != null)
1957
                                        {
1958
                                            step.EndLocation.Lat = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
1959
                                        }
1960
 
1961
                                        pt = nn.SelectSingleNode("lng");
1962
                                        if (pt != null)
1963
                                        {
1964
                                            step.EndLocation.Lng = double.Parse(pt.InnerText, CultureInfo.InvariantCulture);
1965
                                        }
1966
                                    }
1967
 
1968
                                    nn = s.SelectSingleNode("duration");
1969
                                    if (nn != null)
1970
                                    {
1971
                                        nn = nn.SelectSingleNode("text");
1972
                                        if (nn != null)
1973
                                        {
1974
                                            step.Duration = nn.InnerText;
1975
                                            Debug.WriteLine("duration: " + step.Duration);
1976
                                        }
1977
                                    }
1978
 
1979
                                    nn = s.SelectSingleNode("distance");
1980
                                    if (nn != null)
1981
                                    {
1982
                                        nn = nn.SelectSingleNode("text");
1983
                                        if (nn != null)
1984
                                        {
1985
                                            step.Distance = nn.InnerText;
1986
                                            Debug.WriteLine("distance: " + step.Distance);
1987
                                        }
1988
                                    }
1989
 
1990
                                    nn = s.SelectSingleNode("html_instructions");
1991
                                    if (nn != null)
1992
                                    {
1993
                                        step.HtmlInstructions = nn.InnerText;
1994
                                        Debug.WriteLine("html_instructions: " + step.HtmlInstructions);
1995
                                    }
1996
 
1997
                                    nn = s.SelectSingleNode("polyline");
1998
                                    if (nn != null)
1999
                                    {
2000
                                        nn = nn.SelectSingleNode("points");
2001
                                        if (nn != null)
2002
                                        {
2003
                                            step.Points = new List<PointLatLng>();
2004
                                            DecodePointsInto(step.Points, nn.InnerText);
2005
                                        }
2006
                                    }
2007
 
2008
                                    direction.Steps.Add(step);
2009
                                }
2010
                            }
2011
                        }
2012
                    }
2013
                }
2014
            }
2015
            catch (Exception ex)
2016
            {
2017
                direction = null;
2018
                ret = DirectionsStatusCode.ExceptionInCode;
2019
                Debug.WriteLine("GetDirectionsUrl: " + ex);
2020
            }
2021
            return ret;
2022
        }
2023
 
2024
        static void DecodePointsInto(List<PointLatLng> path, string encodedPath)
2025
        {
2026
            // https://github.com/googlemaps/google-maps-services-java/blob/master/src/main/java/com/google/maps/internal/PolylineEncoding.java
2027
            int len = encodedPath.Length;
2028
            int index = 0;
2029
            int lat = 0;
2030
            int lng = 0;
2031
            while (index < len)
2032
            {
2033
                int result = 1;
2034
                int shift = 0;
2035
                int b;
2036
                do
2037
                {
2038
                    b = encodedPath[index++] - 63 - 1;
2039
                    result += b << shift;
2040
                    shift += 5;
2041
                } while (b >= 0x1f && index < len);
2042
                lat += (result & 1) != 0 ? ~(result >> 1) : (result >> 1);
2043
 
2044
                result = 1;
2045
                shift = 0;
2046
 
2047
                if (index < len)
2048
                {
2049
                    do
2050
                    {
2051
                        b = encodedPath[index++] - 63 - 1;
2052
                        result += b << shift;
2053
                        shift += 5;
2054
                    } while (b >= 0x1f && index < len);
2055
                    lng += (result & 1) != 0 ? ~(result >> 1) : (result >> 1);
2056
                }
2057
 
2058
                path.Add(new PointLatLng(lat * 1e-5, lng * 1e-5));
2059
            }
2060
        }
2061
 
2062
        static readonly string DirectionUrlFormatStr = "http://maps.{7}/maps/api/directions/xml?origin={0}&destination={1}&sensor={2}&language={3}{4}{5}{6}";
2063
        static readonly string DirectionUrlFormatPoint = "http://maps.{9}/maps/api/directions/xml?origin={0},{1}&destination={2},{3}&sensor={4}&language={5}{6}{7}{8}";
2064
        static readonly string DirectionUrlFormatWaypoint = "http://maps.{8}/maps/api/directions/xml?origin={0},{1}&waypoints={2}&destination={9},{10}&sensor={3}&language={4}{5}{6}{7}";
2065
        static readonly string DirectionUrlFormatWaypointStr = "http://maps.{7}/maps/api/directions/xml?origin={0}&waypoints={1}&destination={8}&sensor={2}&language={3}{4}{5}{6}";
2066
 
2067
        #endregion
2068
 
2069
        #endregion
2070
 
2071
        #region -- Maps API for Work --
2072
        /// <summary>
2073
        /// https://developers.google.com/maps/documentation/business/webservices/auth#how_do_i_get_my_signing_key
2074
        /// To access the special features of the Google Maps API for Work you must provide a client ID
2075
        /// when accessing any of the API libraries or services.
2076
        /// When registering for Google Google Maps API for Work you will receive this client ID from Enterprise Support.
2077
        /// All client IDs begin with a gme- prefix. Your client ID is passed as the value of the client parameter.
2078
        /// Generally, you should store your private key someplace safe and read them into your code
2079
        /// </summary>
2080
        /// <param name="clientId"></param>
2081
        /// <param name="privateKey"></param>
2082
        public void SetEnterpriseCredentials(string clientId, string privateKey)
2083
        {
2084
            privateKey = privateKey.Replace("-", "+").Replace("_", "/");
2085
            _privateKeyBytes = Convert.FromBase64String(privateKey);
2086
            _clientId = clientId;
2087
        }
2088
        private byte[] _privateKeyBytes;
2089
 
2090
        private string _clientId = string.Empty;
2091
 
2092
        /// <summary>
2093
        /// Your client ID. To access the special features of the Google Maps API for Work
2094
        /// you must provide a client ID when accessing any of the API libraries or services.
2095
        /// When registering for Google Google Maps API for Work you will receive this client ID
2096
        /// from Enterprise Support. All client IDs begin with a gme- prefix.
2097
        /// </summary>
2098
        public string ClientId
2099
        {
2100
            get
2101
            {
2102
                return _clientId;
2103
            }
2104
        }
2105
 
2106
        string GetSignedUri(Uri uri)
2107
        {
2108
            var builder = new UriBuilder(uri);
2109
            builder.Query = builder.Query.Substring(1) + "&client=" + _clientId;
2110
            uri = builder.Uri;
2111
            string signature = GetSignature(uri);
2112
 
2113
            return uri.Scheme + "://" + uri.Host + uri.LocalPath + uri.Query + "&signature=" + signature;
2114
        }
2115
 
2116
        string GetSignedUri(string url)
2117
        {
2118
            return GetSignedUri(new Uri(url));
2119
        }
2120
 
2121
        string GetSignature(Uri uri)
2122
        {
2123
            byte[] encodedPathQuery = Encoding.ASCII.GetBytes(uri.LocalPath + uri.Query);
2124
            var hashAlgorithm = new HMACSHA1(_privateKeyBytes);
2125
            byte[] hashed = hashAlgorithm.ComputeHash(encodedPathQuery);
2126
            return Convert.ToBase64String(hashed).Replace("+", "-").Replace("/", "_");
2127
        }
2128
        #endregion
2129
    }
2130
 
2131
    /// <summary>
2132
    /// GoogleMap provider
2133
    /// </summary>
2134
    public class GoogleMapProvider : GoogleMapProviderBase
2135
    {
2136
        public static readonly GoogleMapProvider Instance;
2137
 
2138
        GoogleMapProvider()
2139
        {
2140
        }
2141
 
2142
        static GoogleMapProvider()
2143
        {
2144
            Instance = new GoogleMapProvider();
2145
        }
2146
 
2294 - 2147
        public string Version = "m@366000000"; //"m@333000000";
2287 - 2148
 
2149
        #region GMapProvider Members
2150
 
2151
        readonly Guid id = new Guid("D7287DA0-A7FF-405F-8166-B6BAF26D066C");
2152
        public override Guid Id
2153
        {
2154
            get
2155
            {
2156
                return id;
2157
            }
2158
        }
2159
 
2160
        readonly string name = "GoogleMap";
2161
        public override string Name
2162
        {
2163
            get
2164
            {
2165
                return name;
2166
            }
2167
        }
2168
 
2169
        public override PureImage GetTileImage(GPoint pos, int zoom)
2170
        {
2171
            string url = MakeTileImageUrl(pos, zoom, LanguageStr);
2172
 
2173
            return GetTileImageUsingHttp(url);
2174
        }
2175
 
2176
        #endregion
2177
 
2178
        string MakeTileImageUrl(GPoint pos, int zoom, string language)
2179
        {
2180
            string sec1 = string.Empty; // after &x=...
2181
            string sec2 = string.Empty; // after &zoom=...
2182
            GetSecureWords(pos, out sec1, out sec2);
2183
 
2184
            return string.Format(UrlFormat, UrlFormatServer, GetServerNum(pos, 4), UrlFormatRequest, Version, language, pos.X, sec1, pos.Y, zoom, sec2, Server);
2185
        }
2186
 
2187
        static readonly string UrlFormatServer = "mt";
2188
        static readonly string UrlFormatRequest = "vt";
2189
        static readonly string UrlFormat = "http://{0}{1}.{10}/maps/{2}/lyrs={3}&hl={4}&x={5}{6}&y={7}&z={8}&s={9}";
2190
    }
2191
}