"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const dom = require("../../../base/browser/dom.js");
const cancellation = require("../../../base/common/cancellation.js");
const linkedList = require("../../../base/common/linkedList.js");
const map = require("../../../base/common/map.js");
const marshalling = require("../../../base/common/marshalling.js");
const network = require("../../../base/common/network.js");
const resources = require("../../../base/common/resources.js");
const uri = require("../../../base/common/uri.js");
const codeEditorService = require("./codeEditorService.js");
const commands = require("../../../platform/commands/common/commands.js");
const editor = require("../../../platform/editor/common/editor.js");
const opener = require("../../../platform/opener/common/opener.js");
var __decorate = globalThis && globalThis.__decorate || function(decorators, target, key, desc) {
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
    r = Reflect.decorate(decorators, target, key, desc);
  else
    for (var i = decorators.length - 1; i >= 0; i--)
      if (d = decorators[i])
        r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = globalThis && globalThis.__param || function(paramIndex, decorator) {
  return function(target, key) {
    decorator(target, key, paramIndex);
  };
};
var __awaiter = globalThis && globalThis.__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());
  });
};
let CommandOpener = class CommandOpener2 {
  constructor(_commandService) {
    this._commandService = _commandService;
  }
  open(target, options) {
    return __awaiter(this, void 0, void 0, function* () {
      if (!opener.matchesScheme(target, network.Schemas.command)) {
        return false;
      }
      if (!(options === null || options === void 0 ? void 0 : options.allowCommands)) {
        return true;
      }
      if (typeof target === "string") {
        target = uri.URI.parse(target);
      }
      let args = [];
      try {
        args = marshalling.parse(decodeURIComponent(target.query));
      } catch (_a) {
        try {
          args = marshalling.parse(target.query);
        } catch (_b) {
        }
      }
      if (!Array.isArray(args)) {
        args = [args];
      }
      yield this._commandService.executeCommand(target.path, ...args);
      return true;
    });
  }
};
CommandOpener = __decorate([
  __param(0, commands.ICommandService)
], CommandOpener);
let EditorOpener = class EditorOpener2 {
  constructor(_editorService) {
    this._editorService = _editorService;
  }
  open(target, options) {
    return __awaiter(this, void 0, void 0, function* () {
      if (typeof target === "string") {
        target = uri.URI.parse(target);
      }
      const { selection, uri: uri$1 } = opener.extractSelection(target);
      target = uri$1;
      if (target.scheme === network.Schemas.file) {
        target = resources.normalizePath(target);
      }
      yield this._editorService.openCodeEditor({
        resource: target,
        options: Object.assign({ selection, source: (options === null || options === void 0 ? void 0 : options.fromUserGesture) ? editor.EditorOpenSource.USER : editor.EditorOpenSource.API }, options === null || options === void 0 ? void 0 : options.editorOptions)
      }, this._editorService.getFocusedCodeEditor(), options === null || options === void 0 ? void 0 : options.openToSide);
      return true;
    });
  }
};
EditorOpener = __decorate([
  __param(0, codeEditorService.ICodeEditorService)
], EditorOpener);
exports.OpenerService = class OpenerService {
  constructor(editorService, commandService) {
    this._openers = new linkedList.LinkedList();
    this._validators = new linkedList.LinkedList();
    this._resolvers = new linkedList.LinkedList();
    this._resolvedUriTargets = new map.ResourceMap((uri2) => uri2.with({ path: null, fragment: null, query: null }).toString());
    this._externalOpeners = new linkedList.LinkedList();
    this._defaultExternalOpener = {
      openExternal: (href) => __awaiter(this, void 0, void 0, function* () {
        if (opener.matchesSomeScheme(href, network.Schemas.http, network.Schemas.https)) {
          dom.windowOpenNoOpener(href);
        } else {
          window.location.href = href;
        }
        return true;
      })
    };
    this._openers.push({
      open: (target, options) => __awaiter(this, void 0, void 0, function* () {
        if ((options === null || options === void 0 ? void 0 : options.openExternal) || opener.matchesSomeScheme(target, network.Schemas.mailto, network.Schemas.http, network.Schemas.https, network.Schemas.vsls)) {
          yield this._doOpenExternal(target, options);
          return true;
        }
        return false;
      })
    });
    this._openers.push(new CommandOpener(commandService));
    this._openers.push(new EditorOpener(editorService));
  }
  registerOpener(opener2) {
    const remove = this._openers.unshift(opener2);
    return { dispose: remove };
  }
  registerValidator(validator) {
    const remove = this._validators.push(validator);
    return { dispose: remove };
  }
  registerExternalUriResolver(resolver) {
    const remove = this._resolvers.push(resolver);
    return { dispose: remove };
  }
  setDefaultExternalOpener(externalOpener) {
    this._defaultExternalOpener = externalOpener;
  }
  registerExternalOpener(opener2) {
    const remove = this._externalOpeners.push(opener2);
    return { dispose: remove };
  }
  open(target, options) {
    var _a;
    return __awaiter(this, void 0, void 0, function* () {
      const targetURI = typeof target === "string" ? uri.URI.parse(target) : target;
      const validationTarget = (_a = this._resolvedUriTargets.get(targetURI)) !== null && _a !== void 0 ? _a : target;
      for (const validator of this._validators) {
        if (!(yield validator.shouldOpen(validationTarget))) {
          return false;
        }
      }
      for (const opener2 of this._openers) {
        const handled = yield opener2.open(target, options);
        if (handled) {
          return true;
        }
      }
      return false;
    });
  }
  resolveExternalUri(resource, options) {
    return __awaiter(this, void 0, void 0, function* () {
      for (const resolver of this._resolvers) {
        try {
          const result = yield resolver.resolveExternalUri(resource, options);
          if (result) {
            if (!this._resolvedUriTargets.has(result.resolved)) {
              this._resolvedUriTargets.set(result.resolved, resource);
            }
            return result;
          }
        } catch (_a) {
        }
      }
      throw new Error("Could not resolve external URI: " + resource.toString());
    });
  }
  _doOpenExternal(resource, options) {
    return __awaiter(this, void 0, void 0, function* () {
      const uri$1 = typeof resource === "string" ? uri.URI.parse(resource) : resource;
      let externalUri;
      try {
        externalUri = (yield this.resolveExternalUri(uri$1, options)).resolved;
      } catch (_a) {
        externalUri = uri$1;
      }
      let href;
      if (typeof resource === "string" && uri$1.toString() === externalUri.toString()) {
        href = resource;
      } else {
        href = encodeURI(externalUri.toString(true));
      }
      if (options === null || options === void 0 ? void 0 : options.allowContributedOpeners) {
        const preferredOpenerId = typeof (options === null || options === void 0 ? void 0 : options.allowContributedOpeners) === "string" ? options === null || options === void 0 ? void 0 : options.allowContributedOpeners : void 0;
        for (const opener2 of this._externalOpeners) {
          const didOpen = yield opener2.openExternal(href, {
            sourceUri: uri$1,
            preferredOpenerId
          }, cancellation.CancellationToken.None);
          if (didOpen) {
            return true;
          }
        }
      }
      return this._defaultExternalOpener.openExternal(href, { sourceUri: uri$1 }, cancellation.CancellationToken.None);
    });
  }
  dispose() {
    this._validators.clear();
  }
};
exports.OpenerService = __decorate([
  __param(0, codeEditorService.ICodeEditorService),
  __param(1, commands.ICommandService)
], exports.OpenerService);
