/**
 * Functions for rendering the ACL User Interface.
 * See https://github.com/solidos/userguide/blob/main/views/sharing/userguide.md#view
 * for a screenshot.
 * @packageDocumentation
 */
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import ns from '../ns';
import * as utils from '../utils';
import { getACLorDefault, getProspectiveHolder } from './acl';
import { AccessController } from './access-controller';
import { style } from '../style';
import { log, warn } from '../debug';
let global = window;
const preventBrowserDropEventsDone = Symbol('prevent double triggering of drop event');
/**
 * See https://coshx.com/preventing-drag-and-drop-disasters-with-a-chrome-userscript
 * Without this dropping anything onto a browser page will cause chrome etc to jump to diff page
 * throwing away all the user's work.
 *
 * In apps which may use drag and drop, this utility takes care of the fact
 * by default in a browser, an uncaught user drop into a browser window
 * causes the browser to lose all its work in that window and navigate to another page
 *
 * @param document  The DOM
 * @returns void
 */
export function preventBrowserDropEvents(document) {
    log('preventBrowserDropEvents called.');
    if (typeof global !== 'undefined') {
        if (global[preventBrowserDropEventsDone])
            return;
        global[preventBrowserDropEventsDone] = true;
    }
    document.addEventListener('drop', handleDrop, false);
    document.addEventListener('dragenter', preventDrag, false);
    document.addEventListener('dragover', preventDrag, false);
}
/** @internal */
export function preventDrag(e) {
    e.stopPropagation();
    e.preventDefault();
}
/** @internal */
export function handleDrop(e) {
    if (e.dataTransfer.files.length > 0) {
        if (!global.confirm('Are you sure you want to drop this file here? (Cancel opens it in a new tab)')) {
            e.stopPropagation();
            e.preventDefault();
            log('@@@@ document-level DROP suppressed: ' + e.dataTransfer.dropEffect);
        }
    }
}
/**
 * Get a folder's own filename in the directory tree. Also works for
 * domain names; the URL protocol ('https://') acts as the tree root
 * with short name '/' (see also test/unit/acl/acl-control.test.ts).
 *
 * ```typescript
 * shortNameForFolder($rdf.namedNode('http://example.com/some/folder/'))
 * // 'folder'
 *
 * shortNameForFolder($rdf.namedNode('http://example.com/some/folder'))
 * // 'folder'
 *
 * shortNameForFolder($rdf.namedNode('http://example.com/'))
 * // 'example.com'
 *
 * shortNameForFolder($rdf.namedNode('http://example.com'))
 * // 'example.com'
 *
 * shortNameForFolder($rdf.namedNode('http://'))
 * // '/'
 * ```
 *
 * It also works with relative URLs:
 * ```typescript
 * shortNameForFolder($rdf.namedNode('../folder/'))
 * // 'folder'
 * ```
 *
 * @param x  RDF Node for the folder URL
 * @returns  Short name for the folder
 */
export function shortNameForFolder(x) {
    let str = x.uri;
    // Strip the trailing slash
    if (str.slice(-1) === '/') {
        str = str.slice(0, -1);
    }
    // Remove the path if present, keeping only the part
    // after the last slash.
    const slash = str.lastIndexOf('/');
    if (slash >= 0) {
        str = str.slice(slash + 1);
    }
    // Return the folder's filename, or '/' if nothing found
    // (but see https://github.com/solidos/solid-ui/issues/196
    // regarding whether this happens at the domain root or
    // not)
    return str || '/';
}
/**
 * A wrapper that retrieves ACL data and uses it
 * to render an [[AccessController]] component.
 * Presumably the '5' is a version number of some sort,
 * but all we know is it was already called ACLControlBox5
 * when it was introduced into solid-ui in
 * https://github.com/solidos/solid-ui/commit/948b874bd93e7bf5160e6e224821b888f07d15f3#diff-4192a29f38a0ababd563b36b47eba5bbR54
 */
export function ACLControlBox5(subject, context, noun, kb) {
    const dom = context.dom;
    const doc = subject.doc(); // The ACL is actually to the doc describing the thing
    const container = dom.createElement('div');
    container.setAttribute('style', style.aclControlBoxContainer);
    const header = container.appendChild(dom.createElement('h1'));
    header.textContent = `Sharing for ${noun} ${utils.label(subject)}`;
    header.setAttribute('style', style.aclControlBoxHeader);
    const status = container.appendChild(dom.createElement('div'));
    status.setAttribute('style', style.aclControlBoxStatus);
    try {
        loadController(doc, kb, subject, noun, context, dom, status)
            .then(controller => container.appendChild(controller.render()));
    }
    catch (error) {
        status.innerText = error;
    }
    return container;
}
function loadController(doc, kb, subject, noun, context, dom, status) {
    return __awaiter(this, void 0, void 0, function* () {
        return new Promise((resolve, reject) => getACLorDefault(doc, (ok, isDirectACL, targetDoc, targetACLDoc, defaultHolder, defaultACLDoc) => __awaiter(this, void 0, void 0, function* () {
            if (!ok) {
                return reject(new Error(`Error reading ${isDirectACL ? '' : ' default '}ACL. status ${targetDoc}: ${targetACLDoc}`));
            }
            const targetDirectory = getDirectory(targetDoc);
            const targetIsProtected = isStorage(targetDoc, targetACLDoc, kb) || hasProtectedAcl(targetDoc);
            if (!targetIsProtected && targetDirectory) {
                try {
                    const prospectiveDefaultHolder = yield getProspectiveHolder(targetDirectory);
                    return resolve(getController(prospectiveDefaultHolder));
                }
                catch (error) {
                    // No need to show this error in status, but good to warn about it in console
                    warn(error);
                }
            }
            return resolve(getController());
            function getController(prospectiveDefaultHolder) {
                return new AccessController(subject, noun, context, status, targetIsProtected, targetDoc, targetACLDoc, defaultHolder, defaultACLDoc, prospectiveDefaultHolder, kb, dom);
            }
        })));
    });
}
function getDirectory(doc) {
    const str = doc.uri.split('#')[0];
    const p = str.slice(0, -1).lastIndexOf('/');
    const q = str.indexOf('//');
    return (q >= 0 && p < q + 2) || p < 0 ? null : str.slice(0, p + 1);
}
function isStorage(doc, aclDoc, store) {
    // @@ TODO: The methods used for targetIsStorage are HACKs - it should not be relied upon, and work is
    // @@ underway to standardize a behavior that does not rely upon this hack
    // @@ hopefully fixed as part of https://github.com/solidos/data-interoperability-panel/issues/10
    return store.holds(doc, ns.rdf('type'), ns.space('Storage'), aclDoc);
}
function hasProtectedAcl(targetDoc) {
    // @@ TODO: This is hacky way of knowing whether or not a certain ACL file can be removed
    // Hopefully we'll find a better, standardized solution to this - https://github.com/solidos/specification/issues/37
    return targetDoc.uri === targetDoc.site().uri;
}
/** @internal */
export function setGlobalWindow(window) {
    global = window;
}
//# sourceMappingURL=acl-control.js.map