/// <summary>
        /// Updates all fields of a map
        /// </summary>
        /// <param name="map">Map with updated data</param>
        /// <returns>Task</returns>
        public async Task UpdateMap(KartaMap map)
        {
            ReplaceOneResult result = await _MapCollection.ReplaceOneAsync(m => m.Id == map.Id, map);

            if (result.MatchedCount == 0)
            {
                throw new KeyNotFoundException();
            }
        }
        /// <summary>
        /// Renames a map
        /// </summary>
        /// <param name="map">Map with updated data</param>
        /// <returns>Task</returns>
        public async Task RenameMap(KartaMap map)
        {
            UpdateResult result = await _MapCollection.UpdateOneAsync(Builders <KartaMap> .Filter.Eq(f => f.Id, map.Id), Builders <KartaMap> .Update.Set(p => p.Name, map.Name).
                                                                      Set(p => p.ModifiedOn, map.ModifiedOn).
                                                                      Set(p => p.ModifiedBy, map.ModifiedBy));

            if (result.MatchedCount == 0)
            {
                throw new KeyNotFoundException();
            }
        }
        /// <summary>
        /// Deletes a map
        /// </summary>
        /// <param name="map">Map to delete</param>
        /// <returns>Task</returns>
        public async Task DeleteMap(KartaMap map)
        {
            KartaMap existingMap = await GetMapById(map.Id);

            if (existingMap == null)
            {
                throw new NullReferenceException();
            }

            IMongoCollection <KartaMap> recyclingBin = _Database.GetCollection <KartaMap>(KartaMapRecyclingBinCollectionName);
            await recyclingBin.InsertOneAsync(existingMap);

            DeleteResult result = await _MapCollection.DeleteOneAsync(p => p.Id == map.Id);
        }
        /// <summary>
        /// Returns a marker by id
        /// </summary>
        /// <param name="mapId">Map Id</param>
        /// <param name="markerId">Marker Id</param>
        /// <returns>Map marker</returns>
        public async Task <KartaMapNamedMarkerQueryResult> GetMarkerById(string mapId, string markerId)
        {
            KartaMap map = await GetMapById(mapId);

            if (map == null)
            {
                return(null);
            }

            KartaMapNamedMarkerQueryResult marker = FindMarkerById(map, map.ItemMarker, MarkerType.Item, markerId);

            if (marker != null)
            {
                return(marker);
            }

            marker = FindMarkerById(map, map.QuestMarker, MarkerType.Quest, markerId);
            if (marker != null)
            {
                return(marker);
            }

            marker = FindMarkerById(map, map.KirjaPageMarker, MarkerType.KirjaPage, markerId);
            if (marker != null)
            {
                return(marker);
            }

            marker = FindMarkerById(map, map.MapChangeMarker, MarkerType.MapChange, markerId);
            if (marker != null)
            {
                return(marker);
            }

            marker = FindMarkerById(map, map.NoteMarker, MarkerType.Note, markerId);
            if (marker != null)
            {
                return(marker);
            }

            marker = FindMarkerById(map, map.NpcMarker, MarkerType.Npc, markerId);
            if (marker != null)
            {
                return(marker);
            }

            return(null);
        }
        /// <summary>
        /// Finds a marker by its id
        /// </summary>
        /// <param name="map">Map</param>
        /// <param name="markerList">Marker list to search</param>
        /// <param name="markerType">Marker type</param>
        /// <param name="markerId">Marker id</param>
        /// <typeparam name="T">Type of the markers</typeparam>
        /// <returns>Found marker result</returns>
        private KartaMapNamedMarkerQueryResult FindMarkerById <T>(KartaMap map, List <T> markerList, MarkerType markerType, string markerId) where T : MapMarker
        {
            MapMarker marker = markerList.FirstOrDefault(m => m.Id == markerId) as MapMarker;

            if (marker == null)
            {
                return(null);
            }

            KartaMapNamedMarkerQueryResult result = new KartaMapNamedMarkerQueryResult();

            result.MapId      = map.Id;
            result.MapName    = map.Name;
            result.MarkerId   = marker.Id;
            result.MarkerName = marker.ExportName;
            result.MarkerType = markerType.ToString();
            return(result);
        }
        /// <summary>
        /// Creates a Karta map
        /// </summary>
        /// <param name="map">Map to create</param>
        /// <returns>Created map, with filled id</returns>
        public async Task <KartaMap> CreateMap(KartaMap map)
        {
            if (string.IsNullOrEmpty(map.Id))
            {
                map.Id = Guid.NewGuid().ToString();
            }

            if (map.NpcMarker == null)
            {
                map.NpcMarker = new List <NpcMapMarker>();
            }

            if (map.ItemMarker == null)
            {
                map.ItemMarker = new List <ItemMapMarker>();
            }

            if (map.KirjaPageMarker == null)
            {
                map.KirjaPageMarker = new List <KirjaPageMapMarker>();
            }

            if (map.QuestMarker == null)
            {
                map.QuestMarker = new List <QuestMapMarker>();
            }

            if (map.MapChangeMarker == null)
            {
                map.MapChangeMarker = new List <MapChangeMapMarker>();
            }

            if (map.NoteMarker == null)
            {
                map.NoteMarker = new List <NoteMapMarker>();
            }

            await _MapCollection.InsertOneAsync(map);

            return(map);
        }
        /// <summary>
        /// Extracts the not implemented markers
        /// </summary>
        /// <param name="map">Map</param>
        /// <param name="markers">Markers</param>
        /// <param name="type">Type of the marker</param>
        /// <returns>List of not implemented markers</returns>
        private List <MarkerImplementationQueryResultObject> ExtractNotImplementedMarkers <T>(KartaMap map, List <T> markers, MarkerType type) where T : MapMarker
        {
            if (markers == null)
            {
                return(new List <MarkerImplementationQueryResultObject>());
            }

            return(markers.Where(m => !m.IsImplemented).Select(m => new MarkerImplementationQueryResultObject {
                Id = m.Id,
                MapId = map.Id,
                Name = map.Name,
                Type = type
            }).ToList());
        }
        /// <summary>
        /// Returns a map by its id
        /// </summary>
        /// <param name="id">Id</param>
        /// <returns>Map</returns>
        public async Task <KartaMap> GetMapById(string id)
        {
            KartaMap map = await _MapCollection.Find(p => p.Id == id).FirstOrDefaultAsync();

            return(map);
        }