"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.shouldHaveDataUrl = shouldHaveDataUrl;
exports.getFileName = getFileName;
exports.isUrl = isUrl;
exports.isFeatureService = isFeatureService;
exports.isFeatureLayer = isFeatureLayer;
exports.getFeatureServiceTitle = getFeatureServiceTitle;
exports.getFeatureLayerItem = getFeatureLayerItem;
exports.getFeatureServiceItem = getFeatureServiceItem;
exports.pingUrl = pingUrl;
exports.pingFeatureService = pingFeatureService;
exports.detectDataTypeFromHeader = detectDataTypeFromHeader;
exports.detectDataTypeFromExtension = detectDataTypeFromExtension;
const itemType_1 = require("../../enums/itemType");
const logger_1 = require("../../utils/logger");
const arcgis_rest_request_1 = require("@esri/arcgis-rest-request");
const FEATURE_SERVICE_URL_REGEX = /(feature)server(\/|\/(\d+))?$/i;
/**
 * Feature service / Doc Links Should not have data urls. Let"s exclude them from that.
 *
 * @export
 * @param {string} itemType What type of item is it?
 * @return {*}  {boolean}
 */
function shouldHaveDataUrl(itemType) {
    // Specifically we want to avoid FS / DL from having a data url.
    return !["Feature Service", "Document Link"].includes(itemType);
}
/**
 * Get the file name out of a url. Will return either the
 * hostname, or the pathname if it exists
 *
 * @export
 * @param {string} url Url to get a file name out of
 * @return {*}  {string}
 */
function getFileName(url) {
    let filename;
    try {
        const parsed = new URL(url);
        // If the URL pathname exists, return its last segment,
        // otherwise return the hostname
        filename =
            parsed.pathname !== "/"
                ? parsed.pathname.split("/").pop()
                : parsed.hostname;
    }
    catch (_e) {
        throw new Error(`Error getting file name from data url`);
    }
    return filename;
}
/**
 * Is this a valid url?
 *
 * @param {string} url Url to validate
 * @return {*}  {boolean}
 */
function isUrl(url) {
    // Use try / catch as a simple string "test" will cause new URL() to throw an error.
    try {
        const result = new URL(url);
        // Cast to bool.
        return !!result;
    }
    catch (_e) {
        logger_1.Logger.error(`Error parsing URL`);
        return false;
    }
}
/**
 * Tests if url string is a feature service / layer.
 *
 * @param {string} url URL to test
 * @return {*}  {boolean}
 */
function isFeatureService(url) {
    return FEATURE_SERVICE_URL_REGEX.test(url);
}
/**
 * Is the service a feature service AND is it a layer specifically
 *
 * @param {string} url
 * @return {*}  {boolean}
 */
function isFeatureLayer(url) {
    const results = FEATURE_SERVICE_URL_REGEX.exec(url);
    return results && !!results[3];
}
/**
 * Gets item title from url as a fall back
 *
 * @param {string} url item url
 * @return {*}  {string}
 */
function getFeatureServiceTitle(url) {
    return /\/services\/(.+)\/(feature|map|image)server/i.exec(url)[1];
}
/**
 * Gets item info out of a feature layer item.
 *
 * @export
 * @param url Item URL
 * @param body Item body.
 * @return Item info (title, description, extent, url)
 */
function getFeatureLayerItem(url, body) {
    return {
        title: body.name,
        description: body.description,
        extent: body.extent,
        url,
    };
}
/**
 * Gets item info out of a feature service response (which is not a specific layer)
 *
 * @export
 * @param {*} url
 * @param {*} body
 * @return {*}
 */
function getFeatureServiceItem(url, body) {
    const description = body.serviceDescription || body.description;
    const title = getFeatureServiceTitle(url);
    const extent = body.fullExtent || body.initialExtent;
    return { title, description, extent, url };
}
/**
 * Ping a non FS url and return response status && headers
 *
 * @export
 * @param {string} url Non FS URL
 * @return {*}  {Promise<{ ok: boolean, headers: Headers }>}
 */
async function pingUrl(url) {
    // ensure that we handle any no-cors requirements
    /* istanbul ignore if -- @preserve */
    if ((0, arcgis_rest_request_1.isNoCorsRequestRequired)(url)) {
        await (0, arcgis_rest_request_1.sendNoCorsRequest)(url);
    }
    // If may be possible to use request, and set rawResponse to true and method: HEAD
    const response = await fetch(url, { method: "HEAD" });
    return {
        ok: response.ok,
        headers: response.headers,
    };
}
/**
 * Ping a FS URL and handle matters such as "hidden" success failures.
 *
 * @export
 * @param {string} url
 * @return {*}  {Promise<{ ok: boolean, item?: any }>}
 */
async function pingFeatureService(url) {
    // make sure the response is in json format
    const parsed = new URL(url);
    parsed.searchParams.set("f", "json");
    // ensure that we handle any no-cors requirements
    /* istanbul ignore if -- @preserve */
    if ((0, arcgis_rest_request_1.isNoCorsRequestRequired)(url)) {
        await (0, arcgis_rest_request_1.sendNoCorsRequest)(url);
    }
    // Since the feature service can return a 200 response with error (e.g. for
    // non-existing layer), we can only request the full metadata by a GET, not HEAD
    // request
    const response = await fetch(parsed.href);
    if (!response.ok) {
        return { ok: false };
    }
    const body = await response.json();
    // Exit if the request returns an error
    if (body.error) {
        return { ok: false };
    }
    const getItem = isFeatureLayer(url)
        ? getFeatureLayerItem
        : getFeatureServiceItem;
    const item = getItem(url, body);
    return {
        ok: true,
        item,
    };
}
function detectDataTypeFromHeader(headers) {
    let contentType = headers.get("Content-Type");
    let dataType;
    if (!contentType) {
        return undefined;
    }
    // Only get the "media-type"
    contentType = contentType.split(";").shift();
    if (contentType === "text/csv") {
        dataType = itemType_1.ItemType.CSV;
    }
    else if (contentType === "application/vnd.ms-excel" ||
        contentType ===
            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") {
        dataType = itemType_1.ItemType["Microsoft Excel"];
    }
    else if (contentType === "application/pdf") {
        dataType = itemType_1.ItemType.PDF;
    }
    else if (contentType === "image/jpeg" ||
        contentType === "image/jpg" ||
        contentType === "image/png") {
        dataType = itemType_1.ItemType.Image;
    }
    else if (contentType === "application/geo+json") {
        dataType = itemType_1.ItemType.GeoJson;
    }
    return dataType;
}
function detectDataTypeFromExtension(url) {
    const contentType = url.toLowerCase().split(".").pop();
    let dataType;
    if (contentType === "csv") {
        dataType = itemType_1.ItemType.CSV;
    }
    else if (contentType === "xls" || contentType === "xlsx") {
        dataType = itemType_1.ItemType["Microsoft Excel"];
    }
    else if (contentType === "pdf") {
        dataType = itemType_1.ItemType.PDF;
    }
    else if (contentType === "jpeg" ||
        contentType === "jpg" ||
        contentType === "png") {
        dataType = itemType_1.ItemType.Image;
    }
    else if (contentType === "geojson") {
        dataType = itemType_1.ItemType.GeoJson;
    }
    return dataType;
}
//# sourceMappingURL=_validate-url-helpers.js.map