

function withParentProps(item, parent, childrenKey, prop, currentValue) {
	if (!Array.isArray(parent)) {
		return;
	}

	let currentPropValue = currentValue || parent[prop];

	for (const entry of parent) {
		if (entry[prop]) {
			currentPropValue = entry[prop];
		}

		if (entry === item) {
			return [item, currentPropValue];
		}

		if (entry[childrenKey]) {
			const res = withParentProps(item, entry[childrenKey], childrenKey, prop, currentPropValue);
            if (res[1]) {
              return res;
            }
		}
	}
	return [];
}

function dms (lat, lon) {
  const λh = lat < 0 ? "S" : "N";
  const φh = lon < 0 ? "W" : "E";

  const λn = Math.abs(lat);
  const φn = Math.abs(lon);

  const λi = Math.trunc(λn);
  const φi = Math.trunc(φn);

  const λf = λn - λi;
  const φf = φn - φi;

  const λs = ((λf*3600)%60).toFixed(1);
  const φs = ((φf*3600)%60).toFixed(1);

  const λm = Math.trunc(λf*60);
  const φm = Math.trunc(φf*60);

  const λ =
    String(λi).padStart(2, "0") + "°" +
    String(λm).padStart(2, "0") + "'" +
    String(λs).padStart(4, "0") + '" ' +
    λh;

  const φ =
    String(φi).padStart(3, "0") + "°" +
    String(φm).padStart(2, "0") + "'" +
    String(φs).padStart(4, "0") + '" ' +
    φh;

  return λ+" "+φ;
}

function geometryAsString (item, opts = {}) {
  const key = "key" in opts ? opts.key : "geometry";
  const formatDMS = opts.dms;

  let str = "";

  if (key in item) {
    const geometry = item[key];
    if (geometry && "coordinates" in geometry) {
      if (geometry.type == "Point") {
        if (formatDMS) {
          str = dms(geometry.coordinates[1], geometry.coordinates[0]);
        } else {
          str = `${geometry.coordinates[1].toFixed(6)}, ${geometry.coordinates[0].toFixed(6)}`;
        }
      }

      if (str) {
        if (opts.url) {
          if (typeof opts.url === 'string') {
            str = `[${str}](${opts.url.replace("$x", geometry.coordinates[0]).replace("$y", geometry.coordinates[1])})`;
          } else {
             str = `[${str}](geo:${geometry.coordinates[0]},${geometry.coordinates[1]})`;
          }
        }
      }
    }
  }

  return str;
}

/** Extract preferences by prefix.
 * 
 * This function returns a lambda which, given
 * a key or a prefix, extracts the relevant
 * preferences from the designated preferences
 * store.
 * 
 * For instance, assume preferences = {
 *   "a.b.c.d": 1,
 *   "a.b.e.f": 2,
 *   "g.h": 3
 * }
 * 
 * And λ = preferencesλ(preferences). Then:
 * 
 * λ("a.b") → { "a.b.c.d": 1, "a.b.e.f": 2 }
 * λ("a.b.e.f") → { "a.b.e.f": 2 }
 * λ("g.x", {"g.x.": 99}) → { "g.x.": 99 }
 * λ("a.c", {"g.x.": 99}) → { "g.x.": 99 }
 * 
 * Note from the last  two examples that a default value
 * may be provided and will be returned if a key does
 * not exist or is not searched for.
 */
function preferencesλ (preferences) {

  return function (key, defaults={}) {
    const keys = Object.keys(preferences).filter(str => str.startsWith(key+".") || str == key);

    const settings = {...defaults};
    for (const str of keys) {
      const k = str == key ? str : str.substring(key.length+1);
      const v = preferences[str];
      settings[k] = v;
    }

    return settings;
  }

}


export {
  withParentProps,
  geometryAsString,
  preferencesλ
}
