// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
/**
 * CodeMirror 标签匹配高亮扩展（适配 HTML/XML 标签）
 * 依赖 xml-fold 扩展（用于查找匹配标签），支持标签高亮和跳转功能
 */
(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror", "../fold/xml-fold"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
  "use strict";
  /**
   * 定义“matchTags”配置项（控制标签匹配功能）
   * @param {CodeMirror} cm - 编辑器实例
   * @param {boolean/object} val - 配置值（false=关闭；true=默认配置；object=自定义配置）
   * @param {boolean/object} old - 旧配置（用于初始化时的对比）
   */
  CodeMirror.defineOption("matchTags", false, function(cm, val, old) {
    if (old && old != CodeMirror.Init) {
      cm.off("cursorActivity", doMatchTags);
      cm.off("viewportChange", maybeUpdateMatch);
      clear(cm);
    }
    if (val) {
      cm.state.matchBothTags = typeof val == "object" && val.bothTags;
      cm.on("cursorActivity", doMatchTags);
      cm.on("viewportChange", maybeUpdateMatch);
      doMatchTags(cm);
    }
  });
  /**
   * 清除标签高亮（从DOM中移除高亮标记）
   * @param {CodeMirror} cm - 编辑器实例
   */
  function clear(cm) {
    if (cm.state.tagHit) cm.state.tagHit.clear();
    if (cm.state.tagOther) cm.state.tagOther.clear();
    cm.state.tagHit = cm.state.tagOther = null;
  }
  /**
   * 执行标签匹配并高亮（核心逻辑）
   * @param {CodeMirror} cm - 编辑器实例
   */
  function doMatchTags(cm) {
    cm.state.failedTagMatch = false;
    cm.operation(function() {
      clear(cm);
      if (cm.somethingSelected()) return;
      var cur = cm.getCursor(), range = cm.getViewport();
      range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to);
      var match = CodeMirror.findMatchingTag(cm, cur, range);
      if (!match) return;
      if (cm.state.matchBothTags) {
        var hit = match.at == "open" ? match.open : match.close;
        if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"});
      }
      var other = match.at == "close" ? match.open : match.close;
      if (other)
        cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"});
      else
        cm.state.failedTagMatch = true;
    });
  }
  /**
   * 视图区域变化时尝试更新匹配（仅当之前匹配失败时重试）
   * @param {CodeMirror} cm - 编辑器实例
   */
  function maybeUpdateMatch(cm) {
    if (cm.state.failedTagMatch) doMatchTags(cm);
  }
  /**
   * 注册“跳转到匹配标签”命令（可通过快捷键触发）
   * 功能：选中并跳转到当前标签的匹配标签
   * 示例：cm.execCommand("toMatchingTag");
   */
  CodeMirror.commands.toMatchingTag = function(cm) {
    var found = CodeMirror.findMatchingTag(cm, cm.getCursor());
    if (found) {
      var other = found.at == "close" ? found.open : found.close;
      if (other) cm.extendSelection(other.to, other.from);
    }
  };
});
