"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var PropTypes = require("prop-types");
var React = require("react");
var split_1 = require("./split");
var DiffMatchPatch = require("diff-match-patch");
var DiffComponent = /** @class */ (function (_super) {
    __extends(DiffComponent, _super);
    function DiffComponent(props) {
        var _this = _super.call(this, props) || this;
        _this.state = {
            value: _this.props.value
        };
        _this.onChange = _this.onChange.bind(_this);
        _this.diff = _this.diff.bind(_this);
        return _this;
    }
    DiffComponent.prototype.componentDidUpdate = function () {
        var value = this.props.value;
        if (value !== this.state.value) {
            this.setState({ value: value });
        }
    };
    DiffComponent.prototype.onChange = function (value) {
        this.setState({
            value: value
        });
        if (this.props.onChange) {
            this.props.onChange(value);
        }
    };
    DiffComponent.prototype.diff = function () {
        var dmp = new DiffMatchPatch();
        var lhString = this.state.value[0];
        var rhString = this.state.value[1];
        if (lhString.length === 0 && rhString.length === 0) {
            return [];
        }
        var diff = dmp.diff_main(lhString, rhString);
        dmp.diff_cleanupSemantic(diff);
        var diffedLines = this.generateDiffedLines(diff);
        var codeEditorSettings = this.setCodeMarkers(diffedLines);
        return codeEditorSettings;
    };
    DiffComponent.prototype.generateDiffedLines = function (diff) {
        var C = {
            DIFF_EQUAL: 0,
            DIFF_DELETE: -1,
            DIFF_INSERT: 1
        };
        var diffedLines = {
            left: [],
            right: []
        };
        var cursor = {
            left: 1,
            right: 1
        };
        diff.forEach(function (chunk) {
            var chunkType = chunk[0];
            var text = chunk[1];
            var lines = text.split("\n").length - 1;
            // diff-match-patch sometimes returns empty strings at random
            if (text.length === 0) {
                return;
            }
            var firstChar = text[0];
            var lastChar = text[text.length - 1];
            var linesToHighlight = 0;
            switch (chunkType) {
                case C.DIFF_EQUAL:
                    cursor.left += lines;
                    cursor.right += lines;
                    break;
                case C.DIFF_DELETE:
                    // If the deletion starts with a newline, push the cursor down to that line
                    if (firstChar === "\n") {
                        cursor.left++;
                        lines--;
                    }
                    linesToHighlight = lines;
                    // If the deletion does not include a newline, highlight the same line on the right
                    if (linesToHighlight === 0) {
                        diffedLines.right.push({
                            startLine: cursor.right,
                            endLine: cursor.right
                        });
                    }
                    // If the last character is a newline, we don't want to highlight that line
                    if (lastChar === "\n") {
                        linesToHighlight -= 1;
                    }
                    diffedLines.left.push({
                        startLine: cursor.left,
                        endLine: cursor.left + linesToHighlight
                    });
                    cursor.left += lines;
                    break;
                case C.DIFF_INSERT:
                    // If the insertion starts with a newline, push the cursor down to that line
                    if (firstChar === "\n") {
                        cursor.right++;
                        lines--;
                    }
                    linesToHighlight = lines;
                    // If the insertion does not include a newline, highlight the same line on the left
                    if (linesToHighlight === 0) {
                        diffedLines.left.push({
                            startLine: cursor.left,
                            endLine: cursor.left
                        });
                    }
                    // If the last character is a newline, we don't want to highlight that line
                    if (lastChar === "\n") {
                        linesToHighlight -= 1;
                    }
                    diffedLines.right.push({
                        startLine: cursor.right,
                        endLine: cursor.right + linesToHighlight
                    });
                    cursor.right += lines;
                    break;
                default:
                    throw new Error("Diff type was not defined.");
            }
        });
        return diffedLines;
    };
    // Receives a collection of line numbers and iterates through them to highlight appropriately
    // Returns an object that tells the render() method how to display the code editors
    DiffComponent.prototype.setCodeMarkers = function (diffedLines) {
        if (diffedLines === void 0) { diffedLines = { left: [], right: [] }; }
        var codeEditorSettings = [];
        var newMarkerSet = {
            left: [],
            right: []
        };
        for (var i = 0; i < diffedLines.left.length; i++) {
            var markerObj = {
                startRow: diffedLines.left[i].startLine - 1,
                endRow: diffedLines.left[i].endLine,
                type: "text",
                className: "codeMarker"
            };
            newMarkerSet.left.push(markerObj);
        }
        for (var i = 0; i < diffedLines.right.length; i++) {
            var markerObj = {
                startRow: diffedLines.right[i].startLine - 1,
                endRow: diffedLines.right[i].endLine,
                type: "text",
                className: "codeMarker"
            };
            newMarkerSet.right.push(markerObj);
        }
        codeEditorSettings[0] = newMarkerSet.left;
        codeEditorSettings[1] = newMarkerSet.right;
        return codeEditorSettings;
    };
    DiffComponent.prototype.render = function () {
        var markers = this.diff();
        return (React.createElement(split_1.default, { name: this.props.name, className: this.props.className, focus: this.props.focus, orientation: this.props.orientation, splits: this.props.splits, mode: this.props.mode, theme: this.props.theme, height: this.props.height, width: this.props.width, fontSize: this.props.fontSize, showGutter: this.props.showGutter, onChange: this.onChange, onPaste: this.props.onPaste, onLoad: this.props.onLoad, onScroll: this.props.onScroll, minLines: this.props.minLines, maxLines: this.props.maxLines, readOnly: this.props.readOnly, highlightActiveLine: this.props.highlightActiveLine, showPrintMargin: this.props.showPrintMargin, tabSize: this.props.tabSize, cursorStart: this.props.cursorStart, editorProps: this.props.editorProps, style: this.props.style, scrollMargin: this.props.scrollMargin, setOptions: this.props.setOptions, wrapEnabled: this.props.wrapEnabled, enableBasicAutocompletion: this.props.enableBasicAutocompletion, enableLiveAutocompletion: this.props.enableLiveAutocompletion, value: this.state.value, markers: markers }));
    };
    DiffComponent.propTypes = {
        cursorStart: PropTypes.number,
        editorProps: PropTypes.object,
        enableBasicAutocompletion: PropTypes.bool,
        enableLiveAutocompletion: PropTypes.bool,
        focus: PropTypes.bool,
        fontSize: PropTypes.number,
        height: PropTypes.string,
        highlightActiveLine: PropTypes.bool,
        maxLines: PropTypes.number,
        minLines: PropTypes.number,
        mode: PropTypes.string,
        name: PropTypes.string,
        className: PropTypes.string,
        onLoad: PropTypes.func,
        onPaste: PropTypes.func,
        onScroll: PropTypes.func,
        onChange: PropTypes.func,
        orientation: PropTypes.string,
        readOnly: PropTypes.bool,
        scrollMargin: PropTypes.array,
        setOptions: PropTypes.object,
        showGutter: PropTypes.bool,
        showPrintMargin: PropTypes.bool,
        splits: PropTypes.number,
        style: PropTypes.object,
        tabSize: PropTypes.number,
        theme: PropTypes.string,
        value: PropTypes.array,
        width: PropTypes.string,
        wrapEnabled: PropTypes.bool
    };
    DiffComponent.defaultProps = {
        cursorStart: 1,
        editorProps: {},
        enableBasicAutocompletion: false,
        enableLiveAutocompletion: false,
        focus: false,
        fontSize: 12,
        height: "500px",
        highlightActiveLine: true,
        maxLines: null,
        minLines: null,
        mode: "",
        name: "ace-editor",
        onLoad: null,
        onScroll: null,
        onPaste: null,
        onChange: null,
        orientation: "beside",
        readOnly: false,
        scrollMargin: [0, 0, 0, 0],
        setOptions: {},
        showGutter: true,
        showPrintMargin: true,
        splits: 2,
        style: {},
        tabSize: 4,
        theme: "github",
        value: ["", ""],
        width: "500px",
        wrapEnabled: true
    };
    return DiffComponent;
}(React.Component));
exports.default = DiffComponent;
//# sourceMappingURL=diff.js.map