OsmImport.cs 14.2 KB
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using MapsDb;
using MapsDb.Models;
using Newtonsoft.Json;

namespace MapConsole
{
    class OsmImport
    {
        protected PostgresDbContext _context;
        public OsmImport()
        {
            _context = new PostgresDbContext();
        }
        public async void Index()
        {
            Curl curl = new Curl();
            string result = await curl.SendRequest();
            XmlDocument xDoc = new XmlDocument();
            xDoc.LoadXml(result);
            XmlElement xRoot = xDoc.DocumentElement;
            if (xRoot.Name != "osm") {
                return;
            }
            int nodes, ways, relations;
            nodes = ways = relations = 0;
            foreach (XmlNode child in xRoot) {
                switch(child.Name) {
                    case "node":
                        nodes++;
                        break;
                    case "way":
                        ways++;
                        break;
                    case "relation":
                        relations++;
                        break;
                }
            }
            string answer = "";
            answer += "Nodes count: " + nodes + "\n";
            answer += "Ways count: " + ways + "\n";
            answer += "Relations count: " + relations;
            Console.WriteLine(answer);
        }

        public async void Create()
        {
            string filename = "base.xml";
            int trackId = 1;
            XDocument doc = new XDocument(
                new XElement("library",
                    new XElement("track",
                        new XAttribute("id", trackId++),
                        new XAttribute("genre", "Rap"),
                        new XAttribute("time", "3:24"),
                        new XElement("name", "Who We Be RMX (feat. 2Pac)"),
                        new XElement("artist", "DMX"),
                        new XElement("album", "The Dogz Mixtape: Who's Next?!")
                    ),
                    new XElement("track",
                        new XAttribute("id", trackId++),
                        new XAttribute("genre", "Rap"),
                        new XAttribute("time", "5:06"),
                        new XElement("name", "Angel (ft. Regina Bell)"),
                        new XElement("artist", "DMX"),
                        new XElement("album", "...And Then There Was X")
                    ),
                    new XElement("track",
                        new XAttribute("id", trackId++),
                        new XAttribute("genre", "Break Beat"),
                        new XAttribute("time", "6:16"),
                        new XElement("name", "Dreaming Your Dreams"),
                        new XElement("artist", "Hybrid"),
                        new XElement("album", "Wide Angle")
                    ),
                    new XElement("track",
                        new XAttribute("id", trackId++),
                        new XAttribute("genre", "Break Beat"),
                        new XAttribute("time", "9:38"),
                        new XElement("name", "Finished Symphony"),
                        new XElement("artist", "Hybrid"),
                        new XElement("album", "Wide Angle")
                    )
                )
            );
            FileStream stream = new FileStream(filename, FileMode.Append);
            doc.Save(stream);
            Console.WriteLine(doc.ToString());
        }

        public async void Update()
        {
            string filename = "base.xml";
            FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite);
            XDocument xDoc = XDocument.Load(stream);
            stream.Dispose();
            stream = new FileStream(filename, FileMode.Truncate, FileAccess.ReadWrite);
            foreach (XElement el in xDoc.Root.Elements("track"))
            {
                int id = Int32.Parse(el.Attribute("id").Value);
                    el.SetAttributeValue("id", id + 5);
            }
            xDoc.Save(stream);
            Console.WriteLine(xDoc.ToString());
        }

        public async void Add()
        {
            string filename = "base.xml";
            FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite);
            XDocument doc = XDocument.Load(stream);
            stream.Dispose();
            stream = new FileStream(filename, FileMode.Truncate, FileAccess.ReadWrite);            
            int maxId = doc.Root.Elements("track").Max(t => Int32.Parse(t.Attribute("id").Value));
            XElement track = new XElement("track",
                new XAttribute("id", ++maxId),
                new XAttribute("genre", "Break Beat"),
                new XAttribute("time", "5:35"),
                new XElement("name", "Higher Than A Skyscraper"),
                new XElement("artist", "Hybrid"),
                new XElement("album", "Morning Sci-Fi")
            );
            doc.Root.Add(track);
            doc.Save(stream);
            Console.WriteLine(doc.ToString());
        }

        public async void Delete()
        {
            string filename = "base.xml";
            FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite);
            XDocument doc = XDocument.Load(stream);
            stream.Dispose();
            stream = new FileStream(filename, FileMode.Truncate, FileAccess.ReadWrite);
            // IEnumerable<XElement> tracks = doc.Root.Descendants("track").Where(
            //     t => t.Element("artist").Value == "Hybrid"
            // ).ToList();
            // foreach (XElement t in tracks)
            // {
            //     t.Remove();
            // }
            doc.Root.Descendants("track").Where(
                t => t.Element("artist").Value == "Hybrid"
            ).Remove();
            doc.Save(stream);
            Console.WriteLine(doc.ToString());
        }

        public async Task Relation(int Id)
        {
            await Task.Run(async () => {
                Curl curl = new Curl();
                string result = await curl.GetRelation(Id);
                this.SaveRelation(result);
            });
        }
        public async Task Relation()
        {
            await Task.Run(async () => {
                Curl curl = new Curl();
                string result = await curl.GetRelation(2143112);
                XDocument doc = XDocument.Parse(result);
                IEnumerable<XElement> relations = doc.Root.Elements("relation");
                List<int> relation_ids = new List<int>();
                foreach (XElement relation in relations) {
                    XElement tag = (from t in relation.Elements("tag")
                                    where t.Attribute("k").Value == "ref" select t).SingleOrDefault();
                    if (tag != null) {
                        string name = tag.Attribute("v").Value;
                        if (name.Length == 4) {
                            relation_ids.Add(Int32.Parse(relation.Attribute("id").Value));
                        }
                    }
                }
                foreach (int relation_id in relation_ids) {
                    string relationXml = await curl.GetRelation(relation_id);
                    this.SaveRelation(relationXml);
                }
            });
        }

        protected void SaveRelation(string relation)
        {
            XDocument doc = XDocument.Parse(relation);
            XElement relationEl = doc.Root.Element("relation");
            string relationRemoteId = relationEl.Attribute("id").Value;
            string[] inserted = { 
            };
            if (inserted.Contains(relationRemoteId)) {
                Console.WriteLine("Skipped relation " + relationRemoteId);
                return;
            }
            XElement tag = (from t in relationEl.Elements("tag")
                            where t.Attribute("k").Value == "ref" select t).Single();
            int index = Int32.Parse(tag.Attribute("v").Value.Substring(2));
            Road road = _context.Road.SingleOrDefault(t => t.RoadTypeId == 1 && t.Index == index);
            if (road == null) {
                return ;
            }
            Relation relationDb = _context.Relation.SingleOrDefault(t => t.RemoteId == relationEl.Attribute("id").Value);
            if (relationDb == null) {
                relationDb = new Relation()
                {
                    RemoteId = relationEl.Attribute("id").Value
                };
                _context.Relation.Add(relationDb);
                Console.WriteLine("Relation " + relationDb.RemoteId + " Created for Road M-" + road.Index);
            } else {
                Console.WriteLine("Relation " + relationDb.RemoteId + " Found for Road M-" + road.Index);
            }
            _context.SaveChanges();
            RelationToRoad relationToRoad = _context.RelationToRoad.SingleOrDefault(t => t.RoadId == road.Id && t.RelationId == relationDb.Id);
            if (relationToRoad == null) {
                relationToRoad = new RelationToRoad()
                {
                    RoadId = road.Id,
                    RelationId = relationDb.Id
                };
                _context.RelationToRoad.Add(relationToRoad);
            }
            _context.SaveChanges();
            Console.WriteLine("Relation " + relationDb.RemoteId + " linked to Road M-" + road.Index);  
            this.SaveWays(doc, relationDb.Id);
            Console.WriteLine("Relation " + relationDb.RemoteId +" insertion completed for Road M-" + road.Index);            
        }

        protected void SaveWays(XDocument doc, int relationId)
        {
            XElement relation = doc.Root.Element("relation");
            IEnumerable<string> wayIds =  from t in relation.Elements("member")
                                        where t.Attribute("type").Value == "way"
                                        select t.Attribute("ref").Value;
            int index = 1;
            foreach (string wayId in wayIds)
            {
                XElement wayXml = doc.Root.Elements("way").Where(t => t.Attribute("id").Value == wayId).SingleOrDefault();
                if (wayXml == null) {
                    continue;
                }
                Way way = _context.Way.Where(t => t.RemoteId == wayId).SingleOrDefault();
                if (way == null) {
                    way = new Way()
                    {
                        RemoteId = wayId
                    };
                    _context.Way.Add(way);
                    Console.WriteLine("Way " + wayId + " Created for Relation " + relationId);
                } else {
                    Console.WriteLine("Way " + wayId + " Found for Relation " + relationId);                    
                }
                _context.SaveChanges();
                WayToRelation wayToRelation = _context.WayToRelation.Where(t => t.RelationId == relationId && t.WayId == way.Id).SingleOrDefault();
                if (wayToRelation == null) {
                    wayToRelation = new WayToRelation()
                    {
                        RelationId = relationId,
                        WayId = way.Id,
                        Index = index
                    };
                    _context.WayToRelation.Add(wayToRelation);
                    Console.WriteLine("Way " + way.Id + " to Relation " + relationId + " link was created with Index " + index);
                } else {
                    wayToRelation.Index = index;
                    Console.WriteLine("Way " + way.Id + " to Relation " + relationId + " link was updated with Index " + index);                    
                }
                _context.SaveChanges();
                this.SavePoints(doc, wayId, way.Id);
                Console.WriteLine("Way " + wayId +" insertion completed");
                index++;
            }
        }

        protected void SavePoints(XDocument doc, string wayRemoteId, int wayId)
        {
            XElement wayXml = (from t in doc.Root.Elements("way")
                                where t.Attribute("id").Value == wayRemoteId
                                select t)
                                .SingleOrDefault();
            if (wayXml == null) {
                return;
            }
            int index = 1;
            foreach (XElement pointXml in wayXml.Elements("nd")) {
                string pointId = pointXml.Attribute("ref").Value;
                XElement nodeXml = doc.Root.Elements("node").Where(t => t.Attribute("id").Value == pointId).SingleOrDefault();
                if(nodeXml == null) {
                    continue;
                }
                decimal lat, lon;
                lat = decimal.Parse(nodeXml.Attribute("lat").Value);
                lon = decimal.Parse(nodeXml.Attribute("lon").Value);
                Node node = _context.Node.Where(t => t.RemoteId == pointId).SingleOrDefault();                    
                if (node == null) {
                    node = new Node()
                    {
                        RemoteId = pointId,
                        Lat = lat,
                        Lon = lon,
                    };
                    _context.Node.Add(node);
                    Console.WriteLine("Point " + pointId + " created for Way " + wayId + " at Lat:" + lat + " Lon:" + lon);
                } else {
                    node.Lat = lat;
                    node.Lon = lon;
                    Console.WriteLine("Point " + pointId + " updated for Way " + wayId + " at Lat:" + lat + " Lon:" + lon);
                }
                _context.SaveChanges();
                NodeToWay nodeToWay = _context.NodeToWay.Where(t => t.WayId == wayId && t.NodeId == node.Id).SingleOrDefault();
                if (nodeToWay == null) {
                    nodeToWay = new NodeToWay()
                    {
                        NodeId = node.Id,
                        WayId = wayId,
                        Index = index
                    };
                    _context.NodeToWay.Add(nodeToWay);
                } else {
                    nodeToWay.Index = index;
                }
                _context.SaveChanges();
                Console.WriteLine("Point " + pointId + " linked to Way " + wayId);
                index++; 
            }
        }
    }
}