'use strict';

const baseToolbarButtonRenderer = require('./base-toolbar-button-renderer-ed297ba2.js');
const contentState = require('./content-state-09ffae92.js');
const codeBlock = require('./code-block-e0af90fc.js');
const misc = require('./misc-3d30df91.js');
const actionHandleInterceptor_abstract = require('./action-handle-interceptor.abstract-fd9e3581.js');
require('./dto-renderer-manager-ae5fcbba.js');
require('./type-guard-8fd7909d.js');
require('./breakpoints-ebde4837.js');
require('./ui-32120990.js');
require('./regex-397aba10.js');
require('./typography-4560e7f1.js');
require('./internal-translation-controller-38f68a4c.js');
require('./global-slimmer-registry-7bbdb1f2.js');
require('./change-manager-72f643de.js');
require('./static-subject-title-5829a298.js');
require('./base-renderer-0a3b62b7.js');
require('./dom-node-subject-observer-factory-26bc0450.js');
require('./observer-f49483e8.js');
require('./dom-node-subject-factory-36b5fdbc.js');
require('./ui-fe7a2158.js');
require('./vega-event-id-c08ce3d3.js');
require('./internal-icon-manager-97635798.js');
require('./icon-manager-d14c9a96.js');
require('./create-public-api-runtime-metrics-slimmer-1b8ecfb4.js');
require('./dynamic-slimmer-0050c489.js');
require('./vega-nonce-manager-55854929.js');
require('./try-get-document-c0ebd39a.js');
require('./vega-internal-event-id-87014e4f.js');
require('./constant-57b1ce36.js');
require('./object-b53e9416.js');
require('./string-39438062.js');
require('./dark-mode-style-controller-32fc03b0.js');
require('./tinycolor-polyfill-502efaa8.js');
require('./index-592b4052.js');

const INSERT_FUNCTION_BLOCK = 'INSERT_FUNCTION_BLOCK';
/**
 * Action to insert a function block into the rich text editor.
 *
 * @example focusedBlock.apply(new InsertFunctionBlockAction('IF'))
 * @example host.value.apply(new InsertFunctionBlockAction('IF'))
 */
class InsertFunctionBlockAction extends codeBlock.ModifyContentAction {
  constructor(functionType) {
    super();
    this.type = INSERT_FUNCTION_BLOCK;
    this.functionType = functionType;
  }
}

/**
 * RTE Function Block
 */
class RTEFunctionBlock extends codeBlock.RTEBlock {
  constructor(id) {
    super(id);
    this.type = 'function-block';
    this.children = [];
  }
  /**
   * Creates an RTEFunctionBlock from a VegaFunctionBlock.
   *
   * @param {VegaFunctionBlock} block - The custom block to convert.
   * @param {VegaRTETransformOptions} [options] - Optional transformation options.
   * @returns {RTEFunctionBlock} The resulting RTEFunctionBlock.
   */
  static from(block, options) {
    const functionBlock = new RTEFunctionBlock(block.id);
    const defaultAnnotation = { customClass: ['statement'] };
    let { annotations } = block;
    annotations = annotations
      ? Object.assign(Object.assign({}, annotations), defaultAnnotation) : defaultAnnotation;
    super.convertAnnotationsToMap(functionBlock.annotationMap, annotations);
    functionBlock.children = this.generateBlockChildren(block.children, options, functionBlock);
    return functionBlock;
  }
  /**
   * Converts the RTEFunctionBlock and its children to an HTML string.
   *
   * @returns {string} The HTML string representation of the function block.
   */
  toHtml() {
    const childrenHtml = this.children
      .map((child) => {
      if (child instanceof codeBlock.RTETextBlock) {
        const attrStr = this.getFunctionContentStyle(child);
        return `<div class="statementelement"${attrStr}>${child.getChildrenHtml()}</div>`;
      }
      else {
        return child.toHtml();
      }
    })
      .join('');
    return `<div class="statement">${childrenHtml}</div>`;
  }
  /**
   * @inheritDoc
   */
  clone(parent) {
    const clonedBlock = new RTEFunctionBlock(misc.generateUUID());
    clonedBlock.parent = parent;
    clonedBlock.children = this.children.map((child) => {
      const clonedChild = child.clone(clonedBlock);
      return clonedChild;
    });
    clonedBlock.annotationMap = super.cloneAnnotations();
    return clonedBlock;
  }
  /**
   * @inheritDoc
   */
  getLastNode() {
    return this.children[this.children.length - 1].getLastNode();
  }
  /**
   * @inheritDoc
   */
  isNotEmpty() {
    return this.children.length > 0;
  }
  /**
   * @inheritDoc
   */
  toJSON() {
    return Object.assign(Object.assign({}, super.toJSON()), { id: this.id, type: this.type, children: this.children.map((child) => child.toJSON()) });
  }
  /**
   * Get the style string for function content block, excluding default paragraph styles.
   *
   * @param {RTETextBlock} block - The text block to extract styles from
   * @returns {string} - The style attribute string
   */
  getFunctionContentStyle(block) {
    const blockAnnotationStyle = new codeBlock.RTEAnnotationStyle(block);
    let styles = blockAnnotationStyle.toCssText({ standalone: true });
    const textStyleAnnotation = block.getAnnotationByType('TEXT_STYLE');
    if (textStyleAnnotation && textStyleAnnotation.textStyle === 'paragraph') {
      const defaultParagraphStyles = blockAnnotationStyle.toCssText(undefined, undefined, textStyleAnnotation.renderStyle({ standalone: true }));
      styles = styles.replace(defaultParagraphStyles, '').trim();
    }
    return styles ? ` style="${styles}"` : '';
  }
}

/**
 * Strategy to handle the insertion of a function block into the rich text editor.
 */
class InsertFunctionBlockStrategy extends codeBlock.ActionHandleStrategy {
  /**
   * @inheritDoc
   */
  handleAction(action, target) {
    const { functionType } = action;
    const functionBlock = this.getFunctionBlock(functionType);
    const emptyParagraph = this.createNewParagraph('');
    const referenceBlock = this.getReferenceBlock(target);
    if (referenceBlock) {
      referenceBlock.parent.apply(new codeBlock.InsertChildrenAfterAction(referenceBlock, functionBlock, emptyParagraph));
    }
    else {
      target.apply(new codeBlock.AppendChildrenAction([functionBlock, emptyParagraph]));
    }
    if (emptyParagraph) {
      action.nextFocusNode = emptyParagraph.children[0];
    }
  }
  /**
   * Get a function block based on the specified type.
   *
   * @param {string} type - The type of function block to create.
   * @returns {RTEFunctionBlock} The function block instance.
   */
  getFunctionBlock(type) {
    const id = misc.generateUUID();
    return RTEFunctionBlock.from({
      id: id,
      type: 'function-block',
      children: [
        {
          id: `${id}-1`,
          type: 'logic-control-block',
          statementText: type.toUpperCase(),
        },
        {
          id: `${id}-2`,
          annotations: {
            customClass: ['statementelement'],
          },
          type: 'paragraph',
          nodes: [
            {
              id: `${id}-2-1`,
              type: 'text',
              text: '   ',
            },
          ],
        },
        {
          id: `${id}-3`,
          type: 'logic-control-block',
          statementText: 'SHOW',
        },
        {
          id: `${id}-4`,
          annotations: {
            customClass: ['statementelement'],
          },
          type: 'paragraph',
          nodes: [
            {
              id: `${id}-4-1`,
              type: 'text',
              text: '   ',
            },
          ],
        },
      ],
    });
  }
  /**
   * We need to get the correct block if the current target is a function block element to avoid nesting function blocks.
   *
   * @param {RTEBlock | VegaRTEContent} currentTarget - The current target block or content.
   * @returns {Nullable<RTEBlock>} The reference block.
   */
  getReferenceBlock(currentTarget) {
    if (!(currentTarget instanceof contentState.VegaRTEContent)) {
      const parentBlock = currentTarget.parent;
      if (parentBlock instanceof RTEFunctionBlock) {
        return parentBlock;
      }
      else {
        return currentTarget;
      }
    }
  }
}

/**
 * Class representing a logic control node in the rich text editor.
 */
class RTELogicControlNode extends codeBlock.RTENode {
  constructor(id, text, parent) {
    super(id);
    this.type = 'logic-control-node';
    this.text = '';
    this.text = text;
    this.parent = parent;
  }
  /**
   * Clone the current node instance.
   *
   * @returns {RTELogicControlNode} - A new instance of RTELogicControlNode.
   */
  clone() {
    return new RTELogicControlNode(this.id, this.text, this.parent);
  }
  /**
   * Convert the node to its HTML representation.
   *
   * @returns {string} - The HTML string of the logic control node.
   */
  toHtml() {
    return this.text;
  }
  /**
   * Convert the node to a JSON representation.
   *
   * @returns {unknown} - The JSON object of the statement syntax node.
   */
  toJSON() {
    return {
      id: this.id,
      type: this.type,
      text: this.text,
    };
  }
  /**
   * Get the end offset of the node's range.
   *
   * @returns {number} - The end offset of the node's range.
   */
  getRangeEndOffset() {
    return 1;
  }
  /**
   * Get the container element for the node's range.
   *
   * @returns {Nullable<Node>} - The container node for the range.
   */
  getRangeContainer() {
    const element = codeBlock.stateEntityRenderingRegistry.getDOMByEntity(this);
    if (element) {
      return element.parentElement;
    }
  }
  /**
   * Get the content editable state of the node.
   *
   * @returns {boolean} - The content editable state of the node.
   */
  isContentEditable() {
    return false;
  }
}

/**
 * Class representing a logic control block in the rich text editor.
 */
class RTELogicControlBlock extends codeBlock.RTEBlock {
  constructor(id, statementText, parent) {
    super(id);
    this.type = 'logic-control-block';
    this.children = [];
    this.statementText = '';
    this.statementText = statementText;
    this.children = [new RTELogicControlNode(`${id}-node-1`, statementText, this)];
    if (parent) {
      this.parent = parent;
    }
  }
  /**
   * Create a logic control block from a JSON representation.
   *
   * @param {VegaRTELogicControlBlock} json - The JSON object representing the logic control block.
   * @returns {RTELogicControlBlock} - The created logic control block.
   */
  static from(json) {
    const block = new RTELogicControlBlock(json.id, json.statementText);
    return block;
  }
  /**
   * Check the block is not empty.
   *
   * @returns {boolean} - Always true for logic control block.
   */
  isNotEmpty() {
    return true;
  }
  /**
   * Get the last node of the block.
   *
   * @returns {RTELogicControlNode} - The last node in the block.
   */
  getLastNode() {
    return this.children[this.children.length - 1];
  }
  /**
   * Convert the block to its HTML representation.
   *
   * @returns {string} - The HTML string of the logic control block.
   */
  toHtml() {
    return `<div class='statementsyntax' contenteditable='false'>${this.statementText}</div>`;
  }
  /**
   * Clone the current block instance.
   *
   * @param { RTEFunctionBlock } parent - The parent function block for the cloned instance.
   * @returns {RTELogicControlBlock} - A new instance of RTEStatementSyntaxBlock.
   */
  clone(parent) {
    return new RTELogicControlBlock(this.id, this.statementText, parent);
  }
  /**
   * Get the JSON representation of the block.
   *
   * @returns {VegaRTELogicControlBlock} - The JSON object of the logic control block.
   */
  toJSON() {
    return {
      id: this.id,
      type: this.type,
      statementText: this.statementText,
    };
  }
}

/**
 * Function toolbar button renderer class.
 */
class FunctionToolbarButtonRenderer extends baseToolbarButtonRenderer.VegaRTEToolbarButtonRenderer {
  /**
   * @inheritDoc
   */
  render(h, editorContext) {
    return this.renderDropdown(h, editorContext, {}, [
      this.renderButton(h, editorContext, {
        label: 'Functions',
        showArrowIcon: true,
      }),
      this.renderDropdownListTemplate(h, FunctionToolbarButtonRenderer.FUNCTION_LIST),
    ]);
  }
  /**
   * Overrides the isDisabled method to determine if the button should be disabled.
   *
   * @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
   * @returns {boolean} - true if the button should be disabled, false otherwise.
   */
  isDisabled(editorContext) {
    const context = this.getExtensionContext(editorContext.host);
    if (context) {
      const { host, getSelectedNodes } = context;
      const focusNode = getSelectedNodes()[0];
      let enableInsert = true;
      if (focusNode) {
        enableInsert = codeBlock.ActionHandleStrategyRegistry.canHandle(INSERT_FUNCTION_BLOCK, focusNode.parent);
      }
      return host.disabled || !enableInsert;
    }
    return false;
  }
  /* istanbul ignore next */
  // eslint-disable-next-line jsdoc/require-jsdoc
  handleButtonClick() {
    throw new Error('Method not implemented.');
  }
  /**
   * Handles dropdown click event
   *
   * @param {RTEExtensionFunctionType} itemKey - key of the clicked item
   * @param {VegaRTEToolbarRenderContext} editorContext The render context for the editor.
   */
  handleDropdownClick(itemKey, editorContext) {
    if (editorContext) {
      const context = this.getExtensionContext(editorContext.host);
      if (context) {
        const { host, getSelectedNodes } = context;
        const focusNode = getSelectedNodes()[0];
        const action = new InsertFunctionBlockAction(itemKey);
        if (!focusNode) {
          host.value.apply(action);
        }
        else if (focusNode.parent) {
          focusNode.parent.apply(action);
        }
        if (action.nextFocusNode) {
          host.value.apply(new contentState.UpdateCursorPositionAction(action.nextFocusNode, 1));
        }
      }
    }
  }
}
FunctionToolbarButtonRenderer.FUNCTION_LIST = [
  { key: 'IF', label: 'Conditional' },
  { key: 'FOREACH', label: 'Foreach' },
];

/**
 * Renders a logic control block in the rich text editor.
 */
class RTELogicControlBlockRenderer extends baseToolbarButtonRenderer.VegaRTEExtensionRenderer {
  /**
   * @inheritDoc
   */
  doRender(h, renderData) {
    return h('div', {
      key: renderData.id,
      class: 'statementsyntax',
      ref: this.useRef(renderData),
    }, h('span', {
      key: `${renderData.id}-1`,
      contenteditable: 'false',
      ref: this.useRef(renderData.children[0]),
    }, renderData.statementText));
  }
}

/**
 * Strategy to convert a div with class 'statementsyntax' into an RTELogicControlBlock DTO.
 */
class DivToLogicControlBlockStrategy extends contentState.BlockToRTEBlockStrategyAbstract {
  constructor() {
    super(...arguments);
    this.blockClassName = 'statementsyntax';
  }
  /**
   * @inheritDoc
   */
  canHandle(elementsArray, currentIndex) {
    const element = elementsArray[currentIndex];
    return element &&
      element.nodeType === Node.ELEMENT_NODE &&
      element.classList.contains(this.blockClassName) &&
      this.isFunctionBlockChild(element)
      ? 1
      : 0;
  }
  /**
   * @inheritDoc
   */
  handle(elementsArray) {
    const element = elementsArray[0];
    return RTELogicControlBlock.from({
      id: misc.generateUUID(),
      type: 'logic-control-block',
      statementText: element.innerText,
    });
  }
  /**
   * The logic control block does not have child blocks to append. so this method is intentionally left empty.
   */
  // eslint-disable-next-line @typescript-eslint/no-empty-function
  appendChildBlocks() { }
  /**
   * @inheritDoc
   */
  shouldProceedToElementChildren() {
    return false;
  }
  /**
   * Checks if the given element is a child of a function block
   *
   * @param {HTMLElement} element - The HTML element to check
   * @returns {boolean} True if the element is a child of a function block, false otherwise
   */
  isFunctionBlockChild(element) {
    return !!(element.parentElement && element.parentElement.classList.contains('statement'));
  }
}

/**
 * Strategy to convert a div with class 'statement' into an function block.
 */
class DivToFunctionBlockStrategy extends contentState.ElementToDTOStrategy {
  /**
   * @inheritDoc
   */
  canHandle(elementsArray, currentIndex) {
    const element = elementsArray[currentIndex];
    return element &&
      element.tagName === 'DIV' &&
      element.classList.contains('statement') &&
      element.childNodes.length &&
      element.querySelector('.statementsyntax')
      ? 1
      : 0;
  }
  /**
   * @inheritDoc
   */
  handle() {
    return RTEFunctionBlock.from({
      id: misc.generateUUID(),
      type: 'function-block',
      annotations: {
        customClass: ['statement'],
      },
      children: [],
    });
  }
  /**
   * @inheritDoc
   */
  appendChildBlocks(currentBlock, childBlocks) {
    currentBlock.children = childBlocks.map((block) => {
      block.parent = currentBlock;
      return block;
    });
  }
  /**
   * @inheritDoc
   */
  shouldProceedToElementChildren() {
    return true;
  }
}

/**
 * Strategy to convert a div with class 'statementelement' into an function block.
 */
class DivToFunctionContentStrategy extends DivToLogicControlBlockStrategy {
  constructor() {
    super(...arguments);
    this.blockClassName = 'statementelement';
  }
  /**
   * @inheritDoc
   */
  handle(elementsArray, options) {
    const element = elementsArray[0];
    const annotations = contentState.htmlElementToAnnotationGenerator.generate(codeBlock.RTETextBlock, element);
    const nodes = Array.from(elementsArray[0].childNodes);
    return codeBlock.RTETextBlock.from({
      id: misc.generateUUID(),
      type: 'paragraph',
      annotations: Object.assign({ customClass: [this.blockClassName] }, annotations),
      nodes: this.generateChildNodes(nodes, undefined, options),
    });
  }
}

const functionBlockStylesCss = "div.statement{padding:2px 4px;background:rgba(var(--v-bg-accent3-secondary, 255, 239, 200));border:1px solid rgba(var(--v-bg-accent3-primary, 255, 220, 131));border-radius:4px;display:flex;flex-direction:row;justify-content:flex-start;align-items:stretch;gap:4px}div.statement .statementsyntax{padding:3px 0;line-height:22px}.rich-text-content div.statement .statementsyntax,.rich-text-content div.statement .statementelement{display:inline-block}div.statement+div.statement{margin-top:2px}div.statement .statementsyntax span{color:rgb(38, 42, 255);font-weight:bold}div.statement .statementelement{padding:2px 4px;background:rgba(var(--v-bg-secondary, 245, 247, 247));border:1px solid rgba(var(--v-border-color-input-field, 171, 198, 216));border-radius:4px;margin:0;min-width:8px}";

/**
 * Renderer for Function Block
 */
class RTEFunctionBlockRenderer extends baseToolbarButtonRenderer.VegaRTEExtensionRenderer {
  /**
   * @inheritDoc
   */
  doRender(createElement, renderData) {
    return createElement('div', {
      key: renderData.id,
      class: this.getElementClassName(renderData),
      ref: this.useRef(renderData),
    });
  }
  /**
   * Defines the function block styles to be injected into the RTE scope.
   *
   * @returns {string} - The styles as a string.
   */
  injectRTEScopeStyles() {
    return functionBlockStylesCss;
  }
  /**
   * Gets the class name for the function block element.
   *
   * @param {RTEFunctionBlock} block - The function block.
   * @returns {string} The class name for the function block element.
   */
  getElementClassName(block) {
    let classes = block.getClasses();
    if (classes.indexOf('statement') < 0) {
      classes = 'statement ' + classes;
    }
    return classes.trim();
  }
}

/**
 * Prevent special type input in function block.
 */
class PreventNewParagraphInterceptor extends actionHandleInterceptor_abstract.ActionHandlerInterceptor {
  /**
   * Checks the target block parent whether is function block.
   *
   * @param {InsertNewParagraphAction} _action - the action to be intercepted
   * @param {RTETextBlock} target - the target block
   * @returns {boolean} - true if the target block parent is function block, false otherwise
   */
  canIntercept(_action, target) {
    return target.parent && target.parent instanceof RTEFunctionBlock;
  }
  /**
   * Insert a new paragraph behind of the function block instead of the target block.
   *
   * @param {ActionHandlerExecution} _execution - the original execution function
   * @param {ModifyContentAction} _action - the action to be intercepted
   * @param {RTETextBlock} target - the target block
   */
  intercept(_execution, _action, target) {
    const insertParagraphAction = new contentState.InsertNewParagraphAction(target.children[0], 0);
    insertParagraphAction.isFlushable = true;
    target.parent.apply(insertParagraphAction);
  }
}

/**
 * Insert a new paragraph behind of current function block strategy.
 */
class FunctionBlockInsertParagraphStrategy extends codeBlock.ActionHandleStrategy {
  /**
   * @inheritDoc
   */
  handleAction(action, target) {
    const newParagraph = this.createNewParagraph('');
    if (newParagraph) {
      target.parent.apply(new codeBlock.InsertChildrenAfterAction(target, newParagraph));
      action.newBlock = newParagraph;
      this.focusToNextLine(newParagraph);
    }
  }
  /**
   * Focus to next paragraph.
   *
   * @param {RTETextBlock} block - The paragraph need to focus.
   */
  focusToNextLine(block) {
    const root = this.getRootContent(block);
    if (root) {
      root.apply(new contentState.UpdateCursorPositionAction(block.children[0], 1));
    }
  }
}

const PASTE_PLAIN_TEXT = 'PASTE_PLAIN_TEXT';
/**
 * Action to paste plain text content into function block.
 *
 * @example functionBlock.apply(new PastePlainTextAction('content', range))
 * @example host.value.apply(new PastePlainTextAction('content', range))
 */
class PastePlainTextAction extends codeBlock.ModifyContentAction {
  constructor(blocksToBeInserted, startNode, startOffset) {
    super();
    this.type = PASTE_PLAIN_TEXT;
    this.blocksToBeInserted = blocksToBeInserted;
    this.startNode = startNode;
    this.startOffset = startOffset;
  }
}

/**
 * Prevent special type input in function block.
 */
class PreventPasteContentInterceptor extends PreventNewParagraphInterceptor {
  /**
   * Paste plain text into text block.
   *
   * @param {ActionHandlerExecution} _execution - the original execution function
   * @param {ModifyContentAction} action - the action to be intercepted
   * @param {RTETextBlock} target - the target block
   */
  intercept(_execution, action, target) {
    const { blocksToBeInserted, rteRange } = action;
    let { startNode, startOffset } = action;
    // Set the start offset from rteRange if available, this is to handle the paste issue https://gethired.atlassian.net/browse/VD-7779
    if (rteRange) {
      startNode = rteRange.startNode;
      startOffset = rteRange.startOffset;
    }
    const pastePlainTextAction = new PastePlainTextAction(blocksToBeInserted, startNode, startOffset);
    target.apply(pastePlainTextAction);
  }
}

/**
 * Strategy to handle the paste content into function block.
 */
class PastePlainTextStrategy extends codeBlock.ActionHandleStrategy {
  /**
   * @inheritDoc
   */
  handleAction(action, target) {
    const { blocksToBeInserted, startNode, startOffset } = action;
    if (startNode instanceof codeBlock.RTETextNode) {
      const textNodes = blocksToBeInserted.flatMap((block) => {
        if (block instanceof codeBlock.RTETextBlock) {
          this.copyLinkGroupAnnotations(target.annotationMap, block.annotationMap);
          return block.children;
        }
        return [];
      });
      if (textNodes.length > 0) {
        if (startOffset > 0) {
          target.apply(new codeBlock.InsertChildrenAfterAction(startNode, ...textNodes));
        }
        else {
          target.apply(new codeBlock.InsertChildrenBeforeAction(startNode, ...textNodes));
        }
        this.focusToNextLine(textNodes[textNodes.length - 1], textNodes[textNodes.length - 1].getRangeEndOffset());
      }
    }
  }
  /**
   * Focus to next paragraph.
   *
   * @param {RTETextNode} node - The text node need to focus.
   * @param {number} startOffset - The offset need to focus.
   */
  focusToNextLine(node, startOffset) {
    const root = this.getRootContent(node);
    if (root) {
      root.apply(new contentState.UpdateCursorPositionAction(node, startOffset));
    }
  }
  /**
   * Copy link group annotations from copied block to target block.
   *
   * @param {BlockAnnotations} blockAnnotationMap - The target block annotation map.
   * @param {BlockAnnotations} copiedAnnotationMap - The copied block annotation map.
   */
  copyLinkGroupAnnotations(blockAnnotationMap, copiedAnnotationMap) {
    if (copiedAnnotationMap && copiedAnnotationMap.has(codeBlock.InternalAnnotationTypeEnum.LINK_GROUP)) {
      const copiedLinkGroupAnnotation = copiedAnnotationMap.get(codeBlock.InternalAnnotationTypeEnum.LINK_GROUP);
      if (!blockAnnotationMap.has(codeBlock.InternalAnnotationTypeEnum.LINK_GROUP)) {
        blockAnnotationMap.set(codeBlock.InternalAnnotationTypeEnum.LINK_GROUP, copiedAnnotationMap.get(codeBlock.InternalAnnotationTypeEnum.LINK_GROUP));
      }
      else {
        copiedLinkGroupAnnotation.linkGroups.forEach((nodes, groupKey) => {
          const existingAnnotation = blockAnnotationMap.get(codeBlock.InternalAnnotationTypeEnum.LINK_GROUP);
          existingAnnotation.linkGroups.set(groupKey, nodes);
        });
      }
    }
  }
}

const convertLogicControlBlockStrategy = new DivToLogicControlBlockStrategy();
const convertFunctionContentStrategy = new DivToFunctionContentStrategy();
const convertFunctionBlockStrategy = new DivToFunctionBlockStrategy();
/**
 * Function extension class for Vega Rich Text Editor.
 */
class VegaRTEFunctionExtension extends baseToolbarButtonRenderer.VegaRTEExtension {
  constructor() {
    super();
    this.toolbarButtonRenderer = new FunctionToolbarButtonRenderer();
    this.registerBlockBasicStrategies(RTELogicControlBlock.name);
    this.registerBlockBasicStrategies(RTEFunctionBlock.name);
    this.preventFunctionBlockDefaultInsertNewParagraph();
    this.registerNode('logic-control-block', RTELogicControlBlock);
    this.registerRenderer('logic-control-block', new RTELogicControlBlockRenderer());
    this.registerNode('function-block', RTEFunctionBlock);
    this.registerRenderer('function-block', new RTEFunctionBlockRenderer());
    this.registerToolbarButtonRenderer('functions', this.toolbarButtonRenderer);
    this.registerElementToBlockDTOClassStrategy(convertLogicControlBlockStrategy);
    this.registerElementToBlockDTOClassStrategy(convertFunctionContentStrategy);
    this.registerElementToBlockDTOClassStrategy(convertFunctionBlockStrategy);
  }
  /**
   * Remove the appen children strategies to prevent default insert new paragraph logic in function block
   */
  preventFunctionBlockDefaultInsertNewParagraph() {
    this.unRegisterStrategy(codeBlock.ModifyContentActionType.INSERT_NEW_PARAGRAPH, RTELogicControlBlock.name);
    this.unRegisterStrategy(codeBlock.ModifyContentActionType.APPEND_CHILDREN, RTEFunctionBlock.name);
    this.unRegisterStrategy(codeBlock.ModifyContentActionType.INSERT_CHILDREN_AFTER, RTEFunctionBlock.name);
    this.unRegisterStrategy(codeBlock.ModifyContentActionType.INSERT_CHILDREN_BEFORE, RTEFunctionBlock.name);
    this.unRegisterStrategy(codeBlock.ModifyContentActionType.PASTE_CONTENT, RTELogicControlBlock.name);
    baseToolbarButtonRenderer.VegaRTEExtension.registerActionHandleStrategy(RTEFunctionBlock.name, codeBlock.ModifyContentActionType.INSERT_NEW_PARAGRAPH, new FunctionBlockInsertParagraphStrategy());
  }
}
(() => {
  const insertFunctionBlockStrategy = new InsertFunctionBlockStrategy();
  baseToolbarButtonRenderer.VegaRTEExtension.registerActionHandleStrategy(contentState.VegaRTEContent.name, INSERT_FUNCTION_BLOCK, insertFunctionBlockStrategy);
  baseToolbarButtonRenderer.VegaRTEExtension.registerActionHandleStrategy(codeBlock.RTETextBlock.name, INSERT_FUNCTION_BLOCK, insertFunctionBlockStrategy);
  baseToolbarButtonRenderer.VegaRTEExtension.registerActionHandleStrategy(contentState.RTEImageBlock.name, INSERT_FUNCTION_BLOCK, insertFunctionBlockStrategy);
  baseToolbarButtonRenderer.VegaRTEExtension.registerActionHandleStrategy(RTELogicControlBlock.name, INSERT_FUNCTION_BLOCK, insertFunctionBlockStrategy);
  baseToolbarButtonRenderer.VegaRTEExtension.registerActionHandleStrategy(codeBlock.RTETextBlock.name, PASTE_PLAIN_TEXT, new PastePlainTextStrategy());
  baseToolbarButtonRenderer.VegaRTEExtension.registerActionHandlerInterceptor(codeBlock.RTETextBlock.name, codeBlock.ModifyContentActionType.INSERT_NEW_PARAGRAPH, new PreventNewParagraphInterceptor());
  baseToolbarButtonRenderer.VegaRTEExtension.registerActionHandlerInterceptor(codeBlock.RTETextBlock.name, codeBlock.ModifyContentActionType.PASTE_CONTENT, new PreventPasteContentInterceptor());
})();

exports.VegaRTEFunctionExtension = VegaRTEFunctionExtension;
