import * as _ from 'lodash-es';
export function textAnnotationFromRange(answerTextNode, range) {
    if (selectionHasNothingToUnderline(range)) {
        return undefined;
    }
    const answerNodes = allNodesUnder(answerTextNode);
    const charactersBefore = charactersBeforeContainer(range.startContainer, range.startOffset, answerTextNode);
    const charactersUntilEnd = charactersBeforeContainer(range.endContainer, range.endOffset, answerTextNode);
    const length = charactersUntilEnd - charactersBefore;
    // selectionHasNothingToUnderline won't catch cases where empty selection is between images
    if (length <= 0) {
        return undefined;
    }
    return {
        startIndex: charactersBefore,
        length
    };
    function charactersBeforeContainer(rangeContainer, offset, answerTextNode) {
        const containerIsTag = rangeContainer === answerTextNode;
        const container = containerIsTag ? rangeContainer.childNodes[offset] : rangeContainer;
        const offsetInside = containerIsTag ? 0 : offset;
        const nodesBeforeContainer = _.takeWhile(answerNodes, node => node !== container);
        const nodesBeforeLengthSum = _.sum(nodesBeforeContainer.map(toNodeLength));
        return offsetInside + nodesBeforeLengthSum;
    }
}
export function getOverlappingMessages(currentAnnotations, start, length) {
    const textAnnotations = currentAnnotations.filter(a => a.type === 'text');
    return getOverlappingMessagesFromTextAnnotations(textAnnotations, start, length);
}
export function getOverlappingMessagesFromTextAnnotations(currentAnnotations, start, length) {
    const parted = getOverlappingAnnotations(currentAnnotations, { startIndex: start, length, message: '' });
    return _.compact(parted.overlapping.map(anno => anno.message)).reduceRight((msg, str) => `${str} / ${msg}`, '');
}
export function toNodeLength(node) {
    var _a;
    return node.nodeType === Node.TEXT_NODE ? (_a = node.textContent) === null || _a === void 0 ? void 0 : _a.length : node.nodeName === 'IMG' ? 1 : 0;
}
export function allNodesUnder(el, documentObject = document) {
    let n = null;
    const a = [];
    const walk = documentObject.createTreeWalker(el, NodeFilter.SHOW_TEXT + NodeFilter.SHOW_ELEMENT, null);
    while ((n = walk.nextNode())) {
        a.push(n);
    }
    return a;
}
export function showAndPositionElement(annotationRect, container, popup, topMargin) {
    const style = popup.style;
    if (container) {
        style.display = 'block';
        const containerRect = container.getBoundingClientRect();
        const popupRect = popup.getBoundingClientRect();
        const left = annotationRect.left - containerRect.left;
        const top = annotationRect.bottom - containerRect.top + topMargin;
        style.top = `${String(top)}px`;
        style.left = `${String(left + popupRect.width < containerRect.width - 30 ? left + 20 : containerRect.width - popupRect.width - 20)}px`;
    }
}
export function hasTextSelectedInAnswerText() {
    const selection = window.getSelection();
    return (selection !== null &&
        selectionInAnswerText(selection) &&
        (isRangeSelection(selection) || textSelectedInRange(selection)));
    function selectionInAnswerText(sel) {
        var _a, _b, _c;
        if (sel.type === 'None' || sel.type === 'Caret' || sel.rangeCount === 0) {
            return false;
        }
        const startContainer = sel.getRangeAt(0).startContainer;
        const endContainer = sel.getRangeAt(0).endContainer;
        return (sel.rangeCount > 0 &&
            ((_a = startContainer.parentElement) === null || _a === void 0 ? void 0 : _a.closest('.e-grading-answer')) !== null &&
            ((_b = endContainer.parentElement) === null || _b === void 0 ? void 0 : _b.closest('.e-grading-answer')) !== null &&
            ((_c = startContainer.parentElement) === null || _c === void 0 ? void 0 : _c.closest('.remove-annotation-popup')) === null);
    }
    function isRangeSelection(sel) {
        return (sel === null || sel === void 0 ? void 0 : sel.type) === 'Range';
    }
    function textSelectedInRange(sel) {
        const range = sel.getRangeAt(0);
        return (!!sel.rangeCount &&
            (range.toString().length > 0 ||
                isParentContainer(range.startContainer) ||
                isParentContainer(range.endContainer)));
    }
    function isParentContainer(container) {
        return container.classList.contains('answer');
    }
}
export function selectionHasNothingToUnderline(range) {
    var _a;
    const contents = range.cloneContents();
    const hasImages = Array.from(contents.childNodes).some(x => x instanceof Element && (x.classList.contains('e-image-wrapper') || x.tagName === 'IMG'));
    return ((_a = contents.textContent) === null || _a === void 0 ? void 0 : _a.length) === 0 && !hasImages;
}
export function mergeAnnotation($answerText, newAnnotation, annotations) {
    const parted = getOverlappingAnnotations(annotations, newAnnotation);
    if (parted.overlapping.length > 0) {
        parted.overlapping.push(newAnnotation);
        const mergedStart = _.minBy(parted.overlapping, range => range.startIndex);
        const mergedEnd = _.maxBy(parted.overlapping, range => range.startIndex + range.length);
        const mergedRange = {
            startIndex: mergedStart.startIndex,
            length: mergedEnd.startIndex + mergedEnd.length - mergedStart.startIndex,
            message: newAnnotation.message
        };
        parted.nonOverlapping.push(mergedRange);
    }
    else {
        parted.nonOverlapping.push(newAnnotation);
    }
    return _.sortBy(parted.nonOverlapping, a => a.type === 'line' || a.type === 'rect'
        ? getImageStartIndex(findAttachment($answerText, a.attachmentIndex), $answerText)
        : a.startIndex, a => (a.type === 'rect' ? a.y : a.type === 'line' ? a.y1 : undefined), a => (a.type === 'rect' ? a.x : a.type === 'line' ? a.x1 : undefined));
}
function findAttachment(container, index) {
    return container.querySelectorAll('img').item(index);
}
function getOverlappingAnnotations(annotations, newAnnotation) {
    const partitioned = _.partition(annotations, other => {
        const newEnd = newAnnotation.startIndex + newAnnotation.length;
        const otherEnd = other.startIndex + other.length;
        return ((newAnnotation.startIndex >= other.startIndex && newAnnotation.startIndex <= otherEnd) ||
            (newEnd >= other.startIndex && newEnd <= otherEnd) ||
            (newAnnotation.startIndex <= other.startIndex && newEnd >= otherEnd));
    });
    return { overlapping: partitioned[0], nonOverlapping: partitioned[1] };
}
export function getImageStartIndex($image, $answerText) {
    var _a;
    const range = document.createRange();
    range.selectNode($image);
    return (_a = textAnnotationFromRange($answerText, range)) === null || _a === void 0 ? void 0 : _a.startIndex;
}
export function annotationFromMousePosition(e, { bbox, attachmentIndex, startX, startY, clientX, clientY }) {
    const lineThresholdPx = 10;
    const currentX = clamp((e.clientX - bbox.left) / bbox.width);
    const currentY = clamp((e.clientY - bbox.top) / bbox.height);
    const isVerticalLine = Math.abs(clientX - e.clientX) <= lineThresholdPx;
    const isHorizontalLine = Math.abs(clientY - e.clientY) <= lineThresholdPx;
    const type = isVerticalLine || isHorizontalLine ? 'line' : 'rect';
    switch (type) {
        case 'rect':
            return {
                type: 'rect',
                attachmentIndex,
                x: Math.min(startX, currentX),
                y: Math.min(startY, currentY),
                width: Math.abs(currentX - startX),
                height: Math.abs(currentY - startY),
                message: ''
            };
        case 'line':
            return {
                type: 'line',
                attachmentIndex,
                x1: isVerticalLine ? startX : Math.min(startX, currentX),
                y1: isHorizontalLine ? startY : Math.min(startY, currentY),
                x2: isVerticalLine ? startX : Math.max(startX, currentX),
                y2: isHorizontalLine ? startY : Math.max(startY, currentY),
                message: ''
            };
    }
}
export function imageAnnotationMouseDownInfo(e, image) {
    const targetAnswerText = image.closest('.e-grading-answer');
    const attachmentIndex = Array.from(targetAnswerText.querySelectorAll('img')).findIndex(img => img === image);
    const attachmentWrapper = targetAnswerText.querySelectorAll('.e-image-wrapper').item(attachmentIndex);
    const bbox = attachmentWrapper.getBoundingClientRect();
    const clientX = e.clientX;
    const startX = clamp((clientX - bbox.left) / bbox.width);
    const clientY = e.clientY;
    const startY = clamp((clientY - bbox.top) / bbox.height);
    return { attachmentIndex, bbox, startX, startY, clientX, clientY };
}
function clamp(n) {
    return _.clamp(n, 0, 1);
}
export function preventDefaults(e) {
    e.preventDefault();
    e.stopPropagation();
}
export function toggle(element, isVisible) {
    element.style.display = isVisible ? 'initial' : 'none';
}
export function isDesktopVersion() {
    return matchMedia('(pointer:fine)').matches;
}
//# sourceMappingURL=editAnnotations.js.map