private static InnerLocation MakeInnerLocation(IDictionary<string,XElement> provinceXml, string routeId, bool hidden, Location parentLocation, int recursionCount)
        {
            var innerLocs = recursionCount >= 2 ? Enumerable.Empty<InnerLocation>() :
                            from inner in provinceXml[routeId].Descendants("route")
                            where inner.Element("direction").Value == "In"
                            || inner.Element("direction").Value == "Down"
                            || inner.Element("direction").Value == "Underground"
                            let inrouteId = inner.Element("to").Value
                            select MakeInnerLocation(provinceXml, inrouteId, inner.Element("hidden").Value == "True", null /*FIXME*/, recursionCount+1);
            var type = provinceXml[routeId].Element("type").Value;
            InnerLocation result = null;
            if (type.Contains("city"))
            {
                result = new City()
                {
                    Id = routeId,
                    Name = provinceXml[routeId].Element("name").Value,
                    Type = type,
                    Hidden = hidden,
                    ParentLocation = parentLocation,
                    Skills = (from skill in provinceXml[routeId].Descendants("skill")
                              select Int32.Parse(skill.Value)).ToArray(),
                    Trades = (from trade in provinceXml[routeId].Descendants("trade")
                             select new Trade {
                                 Who = trade.Element("who").Value,
                                 ItemId = trade.Element("item-id").Value,
                                 ItemName = trade.Element("item-name").Value,
                                 Quantity = Int32.Parse(trade.Element("quantity").Value),
                                 Weight = Int32.Parse(trade.Element("weight-per-item").Value,System.Globalization.NumberStyles.AllowThousands),
                                 Price = Int32.Parse(trade.Element("price").Value),
                                 BuySell = (Trade.TradeType) Enum.Parse(typeof(Trade.TradeType),trade.Element("buysell").Value, true)
                             }).ToArray()
                };

            }
            else
            {
                result = new InnerLocation()
                {
                    Id = routeId,
                    Name = provinceXml[routeId].Element("name").Value,
                    Type = type,
                    Hidden = hidden,
                    ParentLocation = parentLocation,
                };
            }
            foreach (var innerloc in innerLocs)
            {
                if (parentLocation == null || innerloc.Id != parentLocation.Id)
                {
                    result.InnerLocations.Add(innerloc);
                    innerloc.ParentLocation = result;
                }
            }
            return result;
        }
        private void FocusCanvasOn(Location loc)
        {
            var size = ProviniaCanvas.RenderSize;
            var toOffset = new Point((loc.X + Map.length) /* * ProviniaCanvas.Scale */ - size.Width / 2, (loc.Y + Map.length) /* * ProviniaCanvas.Scale */- size.Height / 2);

            //----- pan the canvas to the postion ----
            PointAnimation pan = new PointAnimation(toOffset, Duration.Automatic);

            DoubleAnimation zoom = new DoubleAnimation(1.0, Duration.Automatic);

            myStoryboard = new Storyboard();

            myStoryboard.Children.Add(pan);
            Storyboard.SetTargetProperty(pan, new PropertyPath(ZoomableCanvas.OffsetProperty));
            myStoryboard.FillBehavior = FillBehavior.Stop;
            myStoryboard.Completed += new EventHandler((s, e) =>
                {
                    ProviniaCanvas.Offset = toOffset;
                });

            myStoryboard.Children.Add(zoom);
            Storyboard.SetTargetProperty(zoom, new PropertyPath(ZoomableCanvas.ScaleProperty));
            myStoryboard.FillBehavior = FillBehavior.Stop;
            myStoryboard.Completed += new EventHandler((s, e) =>
            {
                ProviniaCanvas.Scale = 1.0;
            });
            myStoryboard.Begin(ProviniaCanvas);
        }