import { range } from 'lodash';
import React from 'react';
import VisibilitySensor from 'react-visibility-sensor';
import { combineLatest, Subject, Subscription } from 'rxjs';
import { filter, switchMap } from 'rxjs/operators';
import { fetchHighlightedFileLines } from '../repo/backend';
import { highlightNode } from '../util/dom';
export class CodeExcerpt extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = {};
        this.tableContainerElement = null;
        this.propsChanges = new Subject();
        this.visibilityChanges = new Subject();
        this.subscriptions = new Subscription();
        this.visibilitySensorOffset = { bottom: -500 };
        this.onChangeVisibility = (isVisible) => {
            this.visibilityChanges.next(isVisible);
        };
        this.setTableContainerElement = (ref) => {
            this.tableContainerElement = ref;
        };
        this.subscriptions.add(combineLatest(this.propsChanges, this.visibilityChanges)
            .pipe(filter(([, isVisible]) => isVisible), switchMap(([{ repoPath, filePath, commitID, isLightTheme }]) => fetchHighlightedFileLines({ repoPath, commitID, filePath, isLightTheme, disableTimeout: true })))
            .subscribe(blobLines => {
            this.setState({ blobLines });
        }, err => {
            this.setState({ blobLines: [] });
            console.error('failed to fetch blob content', err);
        }));
    }
    componentDidMount() {
        this.propsChanges.next(this.props);
    }
    componentWillReceiveProps(nextProps) {
        this.propsChanges.next(nextProps);
    }
    componentDidUpdate(prevProps, prevState) {
        if (this.tableContainerElement) {
            const visibleRows = this.tableContainerElement.querySelectorAll('table tr');
            for (const highlight of this.props.highlightRanges) {
                const code = visibleRows[highlight.line - this.getFirstLine()].lastChild;
                highlightNode(code, highlight.character, highlight.highlightLength);
            }
        }
    }
    componentWillUnmount() {
        this.subscriptions.unsubscribe();
    }
    getFirstLine() {
        return Math.max(0, Math.min(...this.props.highlightRanges.map(r => r.line)) - (this.props.context || 1));
    }
    getLastLine() {
        const lastLine = Math.max(...this.props.highlightRanges.map(r => r.line)) + (this.props.context || 1);
        return this.state.blobLines ? Math.min(lastLine, this.state.blobLines.length) : lastLine;
    }
    render() {
        if (this.state.blobLines && this.state.blobLines.length === 0) {
            // Show in case of error (e.g., repo not added). This at least lets the user click through, at
            // which point they'll see the full error reason (this is better than showing 3 empty lines of an
            // excerpt).
            return null;
        }
        return (React.createElement(VisibilitySensor, { onChange: this.onChangeVisibility, partialVisibility: true, offset: this.visibilitySensorOffset },
            React.createElement("code", { className: `code-excerpt ${this.props.className || ''}` },
                this.state.blobLines && (React.createElement("div", { ref: this.setTableContainerElement, dangerouslySetInnerHTML: { __html: this.makeTableHTML() } })),
                !this.state.blobLines && (React.createElement("table", null,
                    React.createElement("tbody", null, range(this.getFirstLine(), this.getLastLine()).map(i => (React.createElement("tr", { key: i },
                        React.createElement("td", { className: "line" }, i + 1),
                        React.createElement("td", { className: "code" }, " "))))))))));
    }
    makeTableHTML() {
        return ('<table>' + this.state.blobLines.slice(this.getFirstLine(), this.getLastLine() + 1).join('') + '</table>');
    }
}
//# sourceMappingURL=CodeExcerpt.js.map