/* global L -- eslint */
/**
* @file Contain misc functions to get portal info
* @module portal_data
*/
/**
* Search through the links data for all that link from and to a portal. Returns an object with separate lists of in
* and out links. May or may not be as accurate as the portal details, depending on how much data the API returns.
*
* @function getPortalLinks
* @param {string} guid - The GUID of the portal to search for links.
* @returns {Object} An object containing arrays of incoming ('in') and outgoing ('out') link GUIDs.
*/
window.getPortalLinks = function (guid) {
var links = { in: [], out: [] };
$.each(window.links, function (g, l) {
var d = l.options.data;
if (d.oGuid === guid) {
links.out.push(g);
}
if (d.dGuid === guid) {
links.in.push(g);
}
});
return links;
};
/**
* Counts the total number of links (both incoming and outgoing) for a specified portal.
*
* @function getPortalLinksCount
* @param {string} guid - The GUID of the portal.
* @returns {number} The total number of links for the portal.
*/
window.getPortalLinksCount = function (guid) {
var links = window.getPortalLinks(guid);
return links.in.length + links.out.length;
};
/**
* Searches through the fields for all fields that reference a specified portal.
*
* @function getPortalFields
* @param {string} guid - The GUID of the portal to search for fields.
* @returns {Array} An array containing the GUIDs of fields associated with the portal.
*/
window.getPortalFields = function (guid) {
var fields = [];
$.each(window.fields, function (g, f) {
var d = f.options.data;
if (d.points[0].guid === guid || d.points[1].guid === guid || d.points[2].guid === guid) {
fields.push(g);
}
});
return fields;
};
/**
* Counts the total number of fields associated with a specified portal.
*
* @function getPortalFieldsCount
* @param {string} guid - The GUID of the portal.
* @returns {number} The total number of fields associated with the portal.
*/
window.getPortalFieldsCount = function (guid) {
var fields = window.getPortalFields(guid);
return fields.length;
};
/**
* Zooms the map to a specific portal and shows its details if available.
*
* @function zoomToAndShowPortal
* @param {string} guid - The globally unique identifier of the portal.
* @param {L.LatLng|number[]} latlng - The latitude and longitude of the portal.
*/
window.zoomToAndShowPortal = function (guid, latlng) {
window.map.setView(latlng, window.DEFAULT_ZOOM);
// if the data is available, render it immediately. Otherwise defer
// until it becomes available.
if (window.portals[guid]) window.renderPortalDetails(guid);
else window.urlPortal = guid;
};
/**
* Selects a portal by its latitude and longitude.
*
* @function selectPortalByLatLng
* @param {number|Array|L.LatLng} lat - The latitude of the portal
* or an array or L.LatLng object containing both latitude and longitude.
* @param {number} [lng] - The longitude of the portal.
*/
window.selectPortalByLatLng = function (lat, lng) {
if (lng === undefined && lat instanceof Array) {
lng = lat[1];
lat = lat[0];
} else if (lng === undefined && lat instanceof L.LatLng) {
lng = lat.lng;
lat = lat.lat;
}
for (var guid in window.portals) {
var latlng = window.portals[guid].getLatLng();
if (latlng.lat === lat && latlng.lng === lng) {
window.renderPortalDetails(guid);
return;
}
}
// not currently visible
window.urlPortalLL = [lat, lng];
window.map.setView(window.urlPortalLL, window.DEFAULT_ZOOM);
};
(function () {
var cache = {};
var cache_level = 0;
var GC_LIMIT = 15000; // run garbage collector when cache has more that 5000 items
var GC_KEEP = 10000; // keep the 4000 most recent items
/**
* Finds a portal GUID by its position. Searches through currently rendered portals, fields, and links.
* If the portal is not found in the current render, it checks a cache of recently seen portals.
*
* @function
* @name findPortalGuidByPositionE6
* @param {number} latE6 - The latitude in E6 format.
* @param {number} lngE6 - The longitude in E6 format.
* @returns {string|null} The GUID of the portal at the specified location, or null if not found.
*/
window.findPortalGuidByPositionE6 = function (latE6, lngE6) {
var item = cache[latE6 + ',' + lngE6];
if (item) return item[0];
// now try searching through currently rendered portals
for (var guid in window.portals) {
var data = window.portals[guid].options.data;
if (data.latE6 === latE6 && data.lngE6 === lngE6) return guid;
}
// now try searching through fields
for (var fguid in window.fields) {
var points = window.fields[fguid].options.data.points;
for (var i in points) {
var point = points[i];
if (point.latE6 === latE6 && point.lngE6 === lngE6) return point.guid;
}
}
// and finally search through links
for (var lguid in window.links) {
var l = window.links[lguid].options.data;
if (l.oLatE6 === latE6 && l.oLngE6 === lngE6) return l.oGuid;
if (l.dLatE6 === latE6 && l.dLngE6 === lngE6) return l.dGuid;
}
return null;
};
/**
* Pushes a portal GUID and its position into a cache.
*
* @function
* @name pushPortalGuidPositionCache
* @param {string} guid - The GUID of the portal.
* @param {number} latE6 - The latitude in E6 format.
* @param {number} lngE6 - The longitude in E6 format.
*/
window.pushPortalGuidPositionCache = function (guid, latE6, lngE6) {
cache[latE6 + ',' + lngE6] = [guid, Date.now()];
cache_level += 1;
if (cache_level > GC_LIMIT) {
Object.keys(cache) // get all latlngs
.map(function (latlng) {
return [latlng, cache[latlng][1]];
}) // map them to [latlng, timestamp]
.sort(function (a, b) {
return b[1] - a[1];
}) // sort them
.slice(GC_KEEP) // drop the MRU
.forEach(function (item) {
delete cache[item[0]];
}); // delete the rest
cache_level = Object.keys(cache).length;
}
};
})();