"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.createUtilityLogic = createUtilityLogic;
const rdflib_1 = require("rdflib");
const CustomError_1 = require("../logic/CustomError");
const debug = __importStar(require("../util/debug"));
const utils_1 = require("./utils");
function createUtilityLogic(store, aclLogic, containerLogic) {
    async function recursiveDelete(containerNode) {
        try {
            if (containerLogic.isContainer(containerNode)) {
                const aclDocUrl = await aclLogic.findAclDocUrl(containerNode);
                await store.fetcher._fetch(aclDocUrl, { method: 'DELETE' });
                const containerMembers = await containerLogic.getContainerMembers(containerNode);
                await Promise.all(containerMembers.map((url) => recursiveDelete(url)));
            }
            const nodeToStringHere = containerNode.value;
            return store.fetcher._fetch(nodeToStringHere, { method: 'DELETE' });
        }
        catch (e) {
            debug.log(`Please manually remove ${containerNode.value} from your system.`, e);
        }
    }
    /**
     * Create a resource if it really does not exist
     * Be absolutely sure something does not exist before creating a new empty file
     * as otherwise existing could  be deleted.
     * @param doc {NamedNode} - The resource
     */
    async function loadOrCreateIfNotExists(doc) {
        let response;
        try {
            response = await store.fetcher.load(doc);
        }
        catch (err) {
            if (err.response.status === 404) {
                try {
                    await store.fetcher.webOperation('PUT', doc, { data: '', contentType: 'text/turtle' });
                }
                catch (err) {
                    const msg = 'createIfNotExists: PUT FAILED: ' + doc + ': ' + err;
                    throw new CustomError_1.WebOperationError(msg);
                }
                await store.fetcher.load(doc);
            }
            else {
                if (err.response.status === 401) {
                    throw new CustomError_1.UnauthorizedError();
                }
                if (err.response.status === 403) {
                    if ((0, utils_1.differentOrigin)(doc)) {
                        throw new CustomError_1.CrossOriginForbiddenError();
                    }
                    throw new CustomError_1.SameOriginForbiddenError();
                }
                const msg = 'createIfNotExists doc load error NOT 404:  ' + doc + ': ' + err;
                throw new CustomError_1.FetchError(err.status, err.message + msg);
            }
        }
        return response;
    }
    /* Follow link from this doc to another thing, or else make a new link
    **
    ** @returns existing object, or creates it if non existent
    */
    async function followOrCreateLink(subject, predicate, object, doc) {
        await store.fetcher.load(doc);
        const result = store.any(subject, predicate, null, doc);
        if (result)
            return result;
        if (!store.updater.editable(doc)) {
            const msg = `followOrCreateLink: cannot edit ${doc.value}`;
            debug.warn(msg);
            throw new CustomError_1.NotEditableError(msg);
        }
        try {
            await store.updater.update([], [(0, rdflib_1.st)(subject, predicate, object, doc)]);
        }
        catch (err) {
            const msg = `followOrCreateLink: Error making link in ${doc} to ${object}: ${err}`;
            debug.warn(msg);
            throw new CustomError_1.WebOperationError(err);
        }
        try {
            await loadOrCreateIfNotExists(object);
            // store.fetcher.webOperation('PUT', object, { data: '', contentType: 'text/turtle'})
        }
        catch (err) {
            debug.warn(`followOrCreateLink: Error loading or saving new linked document: ${object}: ${err}`);
            throw err;
        }
        return object;
    }
    // Copied from https://github.com/solidos/web-access-control-tests/blob/v3.0.0/test/surface/delete.test.ts#L5
    async function setSinglePeerAccess(options) {
        let str = [
            '@prefix acl: <http://www.w3.org/ns/auth/acl#>.',
            '',
            `<#alice> a acl:Authorization;\n  acl:agent <${options.ownerWebId}>;`,
            `  acl:accessTo <${options.target}>;`,
            `  acl:default <${options.target}>;`,
            '  acl:mode acl:Read, acl:Write, acl:Control.',
            ''
        ].join('\n');
        if (options.accessToModes) {
            str += [
                '<#bobAccessTo> a acl:Authorization;',
                `  acl:agent <${options.peerWebId}>;`,
                `  acl:accessTo <${options.target}>;`,
                `  acl:mode ${options.accessToModes}.`,
                ''
            ].join('\n');
        }
        if (options.defaultModes) {
            str += [
                '<#bobDefault> a acl:Authorization;',
                `  acl:agent <${options.peerWebId}>;`,
                `  acl:default <${options.target}>;`,
                `  acl:mode ${options.defaultModes}.`,
                ''
            ].join('\n');
        }
        const aclDocUrl = await aclLogic.findAclDocUrl((0, rdflib_1.sym)(options.target));
        return store.fetcher._fetch(aclDocUrl, {
            method: 'PUT',
            body: str,
            headers: [
                ['Content-Type', 'text/turtle']
            ]
        });
    }
    async function createEmptyRdfDoc(doc, comment) {
        await store.fetcher.webOperation('PUT', doc.uri, {
            data: `# ${new Date()} ${comment}
  `,
            contentType: 'text/turtle',
        });
    }
    return {
        recursiveDelete,
        setSinglePeerAccess,
        createEmptyRdfDoc,
        followOrCreateLink,
        loadOrCreateIfNotExists
    };
}
//# sourceMappingURL=utilityLogic.js.map