"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const markers = require("../../../platform/markers/common/markers.js");
const lifecycle = require("../../../base/common/lifecycle.js");
const model$1 = require("../model.js");
const themeService = require("../../../platform/theme/common/themeService.js");
const editorColorRegistry = require("../core/editorColorRegistry.js");
const model = require("./model.js");
const range = require("../core/range.js");
const network = require("../../../base/common/network.js");
const event = require("../../../base/common/event.js");
const colorRegistry = require("../../../platform/theme/common/colorRegistry.js");
const map = require("../../../base/common/map.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);
  };
};
class MarkerDecorations extends lifecycle.Disposable {
  constructor(model2) {
    super();
    this.model = model2;
    this._markersData = /* @__PURE__ */ new Map();
    this._register(lifecycle.toDisposable(() => {
      this.model.deltaDecorations([...this._markersData.keys()], []);
      this._markersData.clear();
    }));
  }
  update(markers2, newDecorations) {
    const oldIds = [...this._markersData.keys()];
    this._markersData.clear();
    const ids = this.model.deltaDecorations(oldIds, newDecorations);
    for (let index = 0; index < ids.length; index++) {
      this._markersData.set(ids[index], markers2[index]);
    }
    return oldIds.length !== 0 || ids.length !== 0;
  }
  getMarker(decoration) {
    return this._markersData.get(decoration.id);
  }
}
exports.MarkerDecorationsService = class MarkerDecorationsService extends lifecycle.Disposable {
  constructor(modelService, _markerService) {
    super();
    this._markerService = _markerService;
    this._onDidChangeMarker = this._register(new event.Emitter());
    this._markerDecorations = new map.ResourceMap();
    modelService.getModels().forEach((model2) => this._onModelAdded(model2));
    this._register(modelService.onModelAdded(this._onModelAdded, this));
    this._register(modelService.onModelRemoved(this._onModelRemoved, this));
    this._register(this._markerService.onMarkerChanged(this._handleMarkerChange, this));
  }
  dispose() {
    super.dispose();
    this._markerDecorations.forEach((value) => value.dispose());
    this._markerDecorations.clear();
  }
  getMarker(uri, decoration) {
    const markerDecorations = this._markerDecorations.get(uri);
    return markerDecorations ? markerDecorations.getMarker(decoration) || null : null;
  }
  _handleMarkerChange(changedResources) {
    changedResources.forEach((resource) => {
      const markerDecorations = this._markerDecorations.get(resource);
      if (markerDecorations) {
        this._updateDecorations(markerDecorations);
      }
    });
  }
  _onModelAdded(model2) {
    const markerDecorations = new MarkerDecorations(model2);
    this._markerDecorations.set(model2.uri, markerDecorations);
    this._updateDecorations(markerDecorations);
  }
  _onModelRemoved(model2) {
    const markerDecorations = this._markerDecorations.get(model2.uri);
    if (markerDecorations) {
      markerDecorations.dispose();
      this._markerDecorations.delete(model2.uri);
    }
    if (model2.uri.scheme === network.Schemas.inMemory || model2.uri.scheme === network.Schemas.internal || model2.uri.scheme === network.Schemas.vscode) {
      if (this._markerService) {
        this._markerService.read({ resource: model2.uri }).map((marker) => marker.owner).forEach((owner) => this._markerService.remove(owner, [model2.uri]));
      }
    }
  }
  _updateDecorations(markerDecorations) {
    const markers2 = this._markerService.read({ resource: markerDecorations.model.uri, take: 500 });
    const newModelDecorations = markers2.map((marker) => {
      return {
        range: this._createDecorationRange(markerDecorations.model, marker),
        options: this._createDecorationOption(marker)
      };
    });
    if (markerDecorations.update(markers2, newModelDecorations)) {
      this._onDidChangeMarker.fire(markerDecorations.model);
    }
  }
  _createDecorationRange(model2, rawMarker) {
    let ret = range.Range.lift(rawMarker);
    if (rawMarker.severity === markers.MarkerSeverity.Hint && !this._hasMarkerTag(
      rawMarker,
      1
      /* Unnecessary */
    ) && !this._hasMarkerTag(
      rawMarker,
      2
      /* Deprecated */
    )) {
      ret = ret.setEndPosition(ret.startLineNumber, ret.startColumn + 2);
    }
    ret = model2.validateRange(ret);
    if (ret.isEmpty()) {
      const maxColumn = model2.getLineLastNonWhitespaceColumn(ret.startLineNumber) || model2.getLineMaxColumn(ret.startLineNumber);
      if (maxColumn === 1 || ret.endColumn >= maxColumn) {
        return ret;
      }
      const word = model2.getWordAtPosition(ret.getStartPosition());
      if (word) {
        ret = new range.Range(ret.startLineNumber, word.startColumn, ret.endLineNumber, word.endColumn);
      }
    } else if (rawMarker.endColumn === Number.MAX_VALUE && rawMarker.startColumn === 1 && ret.startLineNumber === ret.endLineNumber) {
      let minColumn = model2.getLineFirstNonWhitespaceColumn(rawMarker.startLineNumber);
      if (minColumn < ret.endColumn) {
        ret = new range.Range(ret.startLineNumber, minColumn, ret.endLineNumber, ret.endColumn);
        rawMarker.startColumn = minColumn;
      }
    }
    return ret;
  }
  _createDecorationOption(marker) {
    let className;
    let color = void 0;
    let zIndex;
    let inlineClassName = void 0;
    let minimap;
    switch (marker.severity) {
      case markers.MarkerSeverity.Hint:
        if (this._hasMarkerTag(
          marker,
          2
          /* Deprecated */
        )) {
          className = void 0;
        } else if (this._hasMarkerTag(
          marker,
          1
          /* Unnecessary */
        )) {
          className = "squiggly-unnecessary";
        } else {
          className = "squiggly-hint";
        }
        zIndex = 0;
        break;
      case markers.MarkerSeverity.Warning:
        className = "squiggly-warning";
        color = themeService.themeColorFromId(editorColorRegistry.overviewRulerWarning);
        zIndex = 20;
        minimap = {
          color: themeService.themeColorFromId(colorRegistry.minimapWarning),
          position: model$1.MinimapPosition.Inline
        };
        break;
      case markers.MarkerSeverity.Info:
        className = "squiggly-info";
        color = themeService.themeColorFromId(editorColorRegistry.overviewRulerInfo);
        zIndex = 10;
        break;
      case markers.MarkerSeverity.Error:
      default:
        className = "squiggly-error";
        color = themeService.themeColorFromId(editorColorRegistry.overviewRulerError);
        zIndex = 30;
        minimap = {
          color: themeService.themeColorFromId(colorRegistry.minimapError),
          position: model$1.MinimapPosition.Inline
        };
        break;
    }
    if (marker.tags) {
      if (marker.tags.indexOf(
        1
        /* Unnecessary */
      ) !== -1) {
        inlineClassName = "squiggly-inline-unnecessary";
      }
      if (marker.tags.indexOf(
        2
        /* Deprecated */
      ) !== -1) {
        inlineClassName = "squiggly-inline-deprecated";
      }
    }
    return {
      description: "marker-decoration",
      stickiness: 1,
      className,
      showIfCollapsed: true,
      overviewRuler: {
        color,
        position: model$1.OverviewRulerLane.Right
      },
      minimap,
      zIndex,
      inlineClassName
    };
  }
  _hasMarkerTag(marker, tag) {
    if (marker.tags) {
      return marker.tags.indexOf(tag) >= 0;
    }
    return false;
  }
};
exports.MarkerDecorationsService = __decorate([
  __param(0, model.IModelService),
  __param(1, markers.IMarkerService)
], exports.MarkerDecorationsService);
