import React, { Component } from "react";
import { LogViewer } from "@equinor/videx-wellog";
import { InterpolatedScaleHandler, } from "@equinor/videx-wellog";
import "!vue-style-loader!css-loader!sass-loader!./styles.scss";
import Ajv from "ajv";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const inputSchema = require("../../../inputSchema/WellLog.json");
// eslint-disable-next-line @typescript-eslint/no-var-requires
const inputTemplateSchema = require("../../../inputSchema/WellLogTemplate.json");
const ajv = new Ajv();
let schemaErrorTemplate = "";
let validateTemplate = null;
try {
    validateTemplate = ajv.compile(inputTemplateSchema);
}
catch (e) {
    schemaErrorTemplate = "Wrong JSON schema for WellLogTemplate. " + String(e);
    console.error(schemaErrorTemplate);
}
let schemaError = "";
let validate = null;
try {
    validate = ajv.compile(inputSchema);
}
catch (e) {
    schemaError = "Wrong JSON schema for WellLog. " + String(e);
    console.error(schemaError);
}
import { select } from "d3";
import { createTracks } from "../utils/tracks";
import { getScaleTrackNum } from "../utils/tracks";
import { getTrackTemplate } from "../utils/tracks";
import { isScaleTrack } from "../utils/tracks";
import { addOrEditGraphTrack, addOrEditGraphTrackPlot, addOrEditStackedTrack, removeGraphTrackPlot, } from "../utils/tracks";
import { getPlotType } from "../utils/tracks";
import { removeOverlay, zoomContent, scrollContentTo, zoomContentTo, setContentBaseDomain, getContentBaseDomain, getContentDomain, getContentZoom, scrollTracksTo, isTrackSelected, selectTrack, getSelectedTrackIndeces, setSelectedTrackIndeces, } from "../utils/log-viewer";
function showSelection(rbelm, pinelm, vCur, vPin, horizontal, logViewer /*LogController*/) {
    if (vCur === undefined) {
        rbelm.style.visibility = "hidden";
        pinelm.style.visibility = "hidden";
        return;
    }
    const pinelm1 = pinelm.firstElementChild;
    const rubberBandSize = 9;
    const offset = rubberBandSize / 2;
    rbelm.style[horizontal ? "left" : "top"] = `${logViewer.scale(vCur) - offset}px`;
    rbelm.style.visibility = "visible";
    if (vPin !== undefined) {
        let min, max;
        if (vPin < vCur) {
            pinelm1.style[horizontal ? "left" : "top"] = `${offset}px`;
            pinelm1.style[horizontal ? "right" : "bottom"] = "";
            min = vPin;
            max = vCur;
        }
        else {
            pinelm1.style[horizontal ? "right" : "bottom"] = `${offset}px`;
            pinelm1.style[horizontal ? "left" : "top"] = "";
            min = vCur;
            max = vPin;
        }
        min = logViewer.scale(min);
        max = logViewer.scale(max);
        const x = min - offset;
        const w = max - min + rubberBandSize;
        pinelm.style[horizontal ? "width" : "height"] = `${w}px`;
        pinelm.style[horizontal ? "left" : "top"] = `${x}px`;
    }
    else {
        pinelm.style.visibility = "hidden";
    }
}
function addRubberbandOverlay(instance, parent) {
    const rubberBandSize = 9;
    const offset = rubberBandSize / 2;
    const rbelm = instance.overlay.create("rubber-band", {
        onMouseMove: (event) => {
            if (parent.selPersistent)
                return;
            const horizontal = parent.props.horizontal;
            const v = horizontal ? event.x : event.y;
            parent.selCurrent = instance.scale.invert(v);
            const rbelm = event.target;
            const pinelm = instance.overlay.elements["pinned"];
            if (rbelm && pinelm) {
                showSelection(rbelm, pinelm, parent.selCurrent, parent.selPinned, horizontal, instance);
            }
        },
        onMouseExit: (event) => {
            if (event.target) {
                // do not hide! event.target.style.visibility = "hidden";
                /* does not exist ?
                if (instance.options.rubberbandExit) {
                    instance.options.rubberbandExit({
                        source: instance,
                    });
                }
                */
            }
        },
    });
    const rb = select(rbelm)
        .classed("rubber-band", true)
        .style(parent.props.horizontal ? "width" : "height", `${rubberBandSize}px`)
        .style(parent.props.horizontal ? "height" : "width", `${100}%`)
        .style("background-color", "rgba(255,0,0,0.1)")
        .style("visibility", "hidden");
    rb.append("div")
        .style(parent.props.horizontal ? "width" : "height", "1px")
        .style(parent.props.horizontal ? "height" : "width", `${100}%`)
        .style(parent.props.horizontal ? "left" : "top", `${offset}px`)
        .style("background-color", "rgba(255,0,0,0.7)")
        .style("position", "relative");
}
function addReadoutOverlay(instance, parent) {
    const elm = instance.overlay.create("depth", {
        onClick: (event) => {
            const { caller, x, y } = event;
            const value = caller.scale.invert(parent.props.horizontal ? x : y);
            if (event.target) {
                event.target.textContent = Number.isFinite(value)
                    ? `Pinned ${parent.props.axisTitles[parent.props.primaryAxis]}: ${value.toFixed(1)}`
                    : "-";
                event.target.style.visibility = "visible";
            }
        },
        onMouseMove: (event) => {
            if (parent.selPersistent)
                return;
            const { caller, x, y } = event;
            const value = caller.scale.invert(parent.props.horizontal ? x : y);
            if (event.target) {
                event.target.textContent = Number.isFinite(value)
                    ? `${parent.props.axisTitles[parent.props.primaryAxis]}: ${value.toFixed(1)}`
                    : "-";
                event.target.style.visibility = "visible";
            }
            parent.setInfo(value);
            parent.onContentSelection();
        },
        onMouseExit: (event) => {
            if (event.target)
                event.target.style.visibility = "hidden";
        },
        onRescale: (event) => {
            if (event.target && event.transform) {
                // event.transform.k could be not valid after add/edit plot
                // so use getContentZoom(instance) to be consistent
                // console.log("zoom=", getContentZoom(instance), event.transform.k)
                parent.onContentRescale();
                event.target.style.visibility = "visible";
                event.target.textContent = `Zoom: x${event.transform.k.toFixed(1)}`;
            }
        },
    });
    elm.style.visibility = "hidden";
    elm.style.display = "inline-block";
    elm.style.padding = "2px";
    elm.style.borderRadius = "4px";
    elm.style.textAlign = "right";
    elm.style.position = "absolute";
    elm.style.backgroundColor = "rgba(0,0,0,0.5)";
    elm.style.color = "white";
    elm.style.right = "5px";
    elm.style.bottom = "5px";
}
function addPinnedValueOverlay(instance, parent) {
    const rubberBandSize = 9;
    const offset = rubberBandSize / 2;
    const pinelm = instance.overlay.create("pinned", {
        onClick: (event) => {
            const horizontal = parent.props.horizontal;
            const v = horizontal ? event.x : event.y;
            const pinelm = event.target;
            if (pinelm) {
                if (pinelm.style.visibility == "visible") {
                    if (!parent.selPersistent) {
                        parent.selPersistent = true;
                    }
                    else {
                        parent.selPersistent = false;
                        parent.selCurrent = instance.scale.invert(v);
                        pinelm.style.visibility = "hidden";
                        parent.selPinned = undefined;
                        parent.onContentSelection();
                    }
                }
                else {
                    parent.selPinned = instance.scale.invert(v);
                    if (parent.selCurrent === undefined)
                        parent.selCurrent = parent.selPinned;
                    const rbelm = instance.overlay.elements["rubber-band"];
                    if (rbelm && pinelm) {
                        showSelection(rbelm, pinelm, parent.selCurrent, parent.selPinned, horizontal, instance);
                    }
                }
            }
        },
        /* keep selection  onMouseExit: (event: OverlayMouseExitEvent): void => {
            if (event.target) event.target.style.visibility = "hidden";
        },*/
    });
    const pin = select(pinelm)
        .classed("pinned", true)
        .style(parent.props.horizontal ? "width" : "height", `${rubberBandSize}px`)
        .style(parent.props.horizontal ? "height" : "width", `${100}%`)
        .style(parent.props.horizontal ? "top" : "left", `${0}px`)
        .style("background-color", "rgba(0,0,0,0.1)")
        .style("position", "absolute")
        .style("visibility", "hidden");
    pin.append("div")
        .style(parent.props.horizontal ? "width" : "height", "1px")
        .style(parent.props.horizontal ? "height" : "width", `${100}%`)
        .style(parent.props.horizontal ? "left" : "top", `${offset}px`)
        .style("background-color", "rgba(0,255,0,0.7)")
        //.style("position", "relative");
        .style("position", "absolute");
}
function initOverlay(instance, parent) {
    instance.overlay.elm.style("overflow", "hidden"); // to clip content selection
    addReadoutOverlay(instance, parent);
    addRubberbandOverlay(instance, parent);
    addPinnedValueOverlay(instance, parent);
}
function createInterpolator(from, to) {
    // 'from' array could be non monotonous (TVD) so could not use binary search
    // Calculate linear interpolation factor between the nodes
    const mul = new Float32Array(from.length);
    const n = from.length;
    for (let i = 0; i < n; i++) {
        if (!i)
            mul[i] = 0;
        else {
            const d = from[i] - from[i - 1];
            mul[i] = d ? (to[i] - to[i - 1]) / d : 1.0;
        }
    }
    return (x, expand) => {
        for (let i = 0; i < n; i++) {
            if (x < from[i]) {
                if (!i)
                    return expand ? to[0] : Number.NaN;
                return (x - from[i]) * mul[i] + to[i];
            }
        }
        return expand ? to[n ? n - 1 : 0] : Number.NaN;
    };
}
function createScaleHandler(primaries, secondaries) {
    const primary2secondary = createInterpolator(primaries, secondaries);
    const secondary2primary = createInterpolator(secondaries, primaries);
    const forward = (v) => {
        // SecondaryAxis => PrimaryAxis
        return secondary2primary(v, false);
    };
    const reverse = (v) => {
        // PrimaryAxis => SecondaryAxis
        return primary2secondary(v, false);
    };
    const interpolator = {
        forward,
        reverse,
        forwardInterpolatedDomain: (domain) => domain.map((v) => secondary2primary(v, true)),
        reverseInterpolatedDomain: (domain) => domain.map((v) => primary2secondary(v, true)),
    };
    return new InterpolatedScaleHandler(interpolator);
}
function setTracksToController(logController, axes, welllog, // JSON Log Format
template, // JSON
colorTables // JSON
) {
    const { tracks, minmaxPrimaryAxis, primaries, secondaries } = createTracks(welllog, axes, template.tracks, template.styles, colorTables);
    logController.reset();
    const scaleHandler = createScaleHandler(primaries, secondaries);
    logController.scaleHandler = scaleHandler;
    logController.domain = minmaxPrimaryAxis;
    logController.setTracks(tracks);
}
function addTrackMouseEventListner(type, area, element, track, func) {
    element.addEventListener(type, (ev) => {
        const plot = null; ///!!
        func({
            track: track,
            plot: plot,
            element: element,
            ev: ev,
            type: type,
            area: area,
        });
        ev.preventDefault();
    });
}
const types = [
    "contextmenu",
    "click",
    "dblclick",
];
const areas = [
    "title",
    "legend",
    "container",
];
function addTrackMouseEventHandlers(elm, track, func) {
    for (const area of areas) {
        const elements = elm.getElementsByClassName("track-" + area);
        for (const element of elements)
            for (const type of types)
                addTrackMouseEventListner(type, area, element, track, func);
    }
}
import ReactDOM from "react-dom";
import { PlotPropertiesDialog } from "./PlotDialog";
import { TrackPropertiesDialog } from "./TrackDialog";
function addPlot(parent, wellLogView, track) {
    const el = document.createElement("div");
    el.style.width = "10px";
    el.style.height = "13px";
    parent.appendChild(el);
    ReactDOM.render(React.createElement(PlotPropertiesDialog, { wellLogView: wellLogView, track: track, onOK: wellLogView.addTrackPlot.bind(wellLogView, track) }), el);
}
function fillPlotTemplate(templateTrack, plot) {
    const options = plot.options;
    const optionsDifferential = plot.options; // DifferentialPlot - 2 series!
    const options1 = optionsDifferential.serie1;
    const options2 = optionsDifferential.serie2;
    const legend = options.legendInfo();
    const legendDifferential = legend; // DifferentialPlot - 2 series!
    const legend1 = legendDifferential.serie1;
    const legend2 = legendDifferential.serie2;
    const scale = (templateTrack === null || templateTrack === void 0 ? void 0 : templateTrack.scale) !== options.scale ? options.scale : undefined;
    return {
        style: undefined,
        type: getPlotType(plot),
        scale: scale == "log" || scale == "linear" ? scale : undefined,
        name: (legend1 && legend1.label ? legend1.label : legend.label) || "",
        name2: legend2 && legend2.label ? legend2.label : "",
        color: (options1 ? options1.color : options.color) || "",
        color2: options2 ? options2.color : "",
        inverseColor: options.inverseColor || "",
        fill: (options1 ? options1.fill : options.fill) || "",
        fill2: options2 ? options2.fill : "",
        colorTable: options.colorTable ? options.colorTable.name : "",
        inverseColorTable: options.inverseColorTable
            ? options.inverseColorTable.name
            : "",
        colorScale: options.colorScale,
        inverseColorScale: options.inverseColorScale,
    };
}
function editPlot(parent, wellLogView, track, templatePlot, onOK) {
    const el = document.createElement("div");
    el.style.width = "10px";
    el.style.height = "13px";
    parent.appendChild(el);
    ReactDOM.render(React.createElement(PlotPropertiesDialog, { templatePlot: templatePlot, wellLogView: wellLogView, track: track, onOK: onOK }), el);
}
export function addTrack(parent, wellLogView, onOK) {
    const el = document.createElement("div");
    el.style.width = "10px";
    el.style.height = "13px";
    parent.appendChild(el);
    ReactDOM.render(React.createElement(TrackPropertiesDialog, { wellLogView: wellLogView, onOK: onOK }), el);
}
export function editTrack(parent, wellLogView, templateTrack, onOK) {
    const el = document.createElement("div");
    el.style.width = "10px";
    el.style.height = "13px";
    parent.appendChild(el);
    ReactDOM.render(React.createElement(TrackPropertiesDialog, { templateTrack: templateTrack, wellLogView: wellLogView, onOK: onOK }), el);
}
function formatSchemaError(validate) {
    const errors = validate.errors;
    if (!errors || !errors[0])
        return "JSON schema validation failed";
    return ((errors[0].dataPath ? errors[0].dataPath + ": " : "") +
        errors[0].message);
}
class WellLogView extends Component {
    constructor(props) {
        super(props);
        if (!props.welllog)
            throw "No props.welllog given in wellLogView component";
        this.container = undefined;
        this.logController = undefined;
        this.selCurrent = undefined;
        this.selPinned = undefined;
        this.selPersistent = undefined;
        this.template = {
            name: "",
            scale: {
                primary: "",
            },
            tracks: [],
            styles: [],
        };
        this.state = {
            infos: [],
            scrollTrackPos: 0,
        };
        this.onTrackMouseEvent = this.onTrackMouseEvent.bind(this);
        // set callback to component's caller
        if (this.props.onCreateController)
            this.props.onCreateController(this);
    }
    componentDidMount() {
        this.createLogViewer();
        this.template = JSON.parse(JSON.stringify(this.props.template)); // save external template content to current
        this.setTracks(true);
    }
    shouldComponentUpdate(nextProps, nextState) {
        if (this.props.horizontal !== nextProps.horizontal)
            return true;
        if (this.props.hideTitles !== nextProps.hideTitles)
            return true;
        if (this.props.hideLegend !== nextProps.hideLegend)
            return true;
        if (this.props.welllog !== nextProps.welllog)
            return true;
        if (this.props.template !== nextProps.template)
            return true;
        if (this.props.colorTables !== nextProps.colorTables)
            return true;
        if (this.props.primaryAxis !== nextProps.primaryAxis)
            return true;
        if (this.props.axisTitles !== nextProps.axisTitles)
            return true;
        if (this.props.axisMnemos !== nextProps.axisMnemos)
            return true;
        if (this.props.maxVisibleTrackNum !== nextProps.maxVisibleTrackNum)
            return true;
        if (this.state.scrollTrackPos !== nextState.scrollTrackPos)
            return true;
        if (this.state.errorText !== nextState.errorText)
            return true;
        if (this.props.maxContentZoom !== nextProps.maxContentZoom)
            return true;
        if (this.props.checkDatafileSchema !== nextProps.checkDatafileSchema)
            return true;
        // callbacks
        return false;
    }
    componentDidUpdate(prevProps, prevState) {
        // Typical usage (don't forget to compare props):
        if (this.props.onCreateController !== prevProps.onCreateController) {
            // update callback to component's caller
            if (this.props.onCreateController)
                this.props.onCreateController(this);
        }
        let selectedTrackIndeces = []; // indeces to restore
        let selection = undefined; // content selection to restore
        let shouldSetTracks = false;
        let checkSchema = false;
        if (this.props.horizontal !== prevProps.horizontal ||
            this.props.hideTitles !== prevProps.hideTitles ||
            this.props.hideLegend !== prevProps.hideLegend ||
            this.props.maxContentZoom !== prevProps.maxContentZoom) {
            selection = this.getContentSelection();
            selectedTrackIndeces = this.getSelectedTrackIndeces();
            this.createLogViewer();
            shouldSetTracks = true;
        }
        if (this.props.welllog !== prevProps.welllog ||
            this.props.checkDatafileSchema !== prevProps.checkDatafileSchema) {
            shouldSetTracks = true;
            checkSchema = true;
        }
        else if (this.props.template !== prevProps.template) {
            this.template = JSON.parse(JSON.stringify(this.props.template)); // save external template content to current
            shouldSetTracks = true;
            checkSchema = true;
        }
        else if (this.props.colorTables !== prevProps.colorTables) {
            selection = this.getContentSelection();
            selectedTrackIndeces = this.getSelectedTrackIndeces();
            shouldSetTracks = true; // force to repaint
        }
        else if (this.props.primaryAxis !== prevProps.primaryAxis) {
            selectedTrackIndeces = this.getSelectedTrackIndeces();
            shouldSetTracks = true;
        }
        else if (this.props.axisTitles !== prevProps.axisTitles ||
            this.props.axisMnemos !== prevProps.axisMnemos) {
            selection = this.getContentSelection();
            selectedTrackIndeces = this.getSelectedTrackIndeces();
            shouldSetTracks = true; //??
        }
        if (shouldSetTracks) {
            this.setTracks(checkSchema); // use this.template
            setSelectedTrackIndeces(this.logController, selectedTrackIndeces);
            if (selection)
                this.selectContent(selection);
        }
        else if (this.state.scrollTrackPos !== prevState.scrollTrackPos ||
            this.props.maxVisibleTrackNum !== prevProps.maxVisibleTrackNum) {
            this.onTrackScroll();
            this.onTrackSelection();
            this.setInfo();
        }
    }
    createLogViewer() {
        this.selPersistent = undefined;
        if (this.logController) {
            // remove old LogViewer
            this.logController.reset(); // clear UI
            this.logController.onUnmount(); //?
            removeOverlay(this.logController); // we should remove it because LogViewer do not delete it
            this.logController = undefined;
        }
        if (this.container) {
            // create new LogViewer
            this.logController = new LogViewer({
                horizontal: this.props.horizontal,
                showTitles: !this.props.hideTitles,
                showLegend: !this.props.hideLegend,
                maxZoom: this.props.maxContentZoom,
                onTrackEnter: (elm, track) => addTrackMouseEventHandlers(elm, track, this.onTrackMouseEvent),
            });
            this.logController.init(this.container);
            initOverlay(this.logController, this);
        }
        this.setInfo();
    }
    getAxesInfo() {
        return {
            primaryAxis: this.props.primaryAxis,
            secondaryAxis: this.props.template &&
                this.props.template.scale &&
                this.props.template.scale.allowSecondary
                ? this.props.primaryAxis == "md"
                    ? "tvd"
                    : "md"
                : "",
            titles: this.props.axisTitles,
            mnemos: this.props.axisMnemos,
        };
    }
    setTracks(checkSchema) {
        this.selCurrent = this.selPinned = undefined; // clear old selection (primary scale could be changed)
        if (checkSchema) {
            //check against the json schema
            let errorTextTemplate = "";
            if (!validateTemplate)
                errorTextTemplate = schemaErrorTemplate;
            else if (!validateTemplate(this.template))
                errorTextTemplate = formatSchemaError(validateTemplate);
            if (errorTextTemplate)
                errorTextTemplate = "Template: " + errorTextTemplate;
            if (this.props.checkDatafileSchema) {
                let errorText = "";
                if (!validate)
                    errorText = schemaError;
                else if (!validate(this.props.welllog))
                    errorText = formatSchemaError(validate);
                if (errorText) {
                    if (errorText)
                        errorText = "Datafile: " + errorText;
                    if (errorTextTemplate)
                        errorTextTemplate += "; ";
                    errorTextTemplate += errorText;
                }
            }
            this.setState({ errorText: errorTextTemplate });
        }
        if (this.logController) {
            const axes = this.getAxesInfo();
            setTracksToController(this.logController, axes, this.props.welllog, this.template, this.props.colorTables);
        }
        this.onTrackScroll();
        this.onTrackSelection();
        this.setInfo(); // Clear old track information
    }
    findTrackById(trackId) {
        var _a;
        return (_a = this.logController) === null || _a === void 0 ? void 0 : _a.tracks.find(function (track) {
            return track.id === trackId;
        });
    }
    /**
      Display current state of track scrolling
      */
    onTrackScroll() {
        const iFrom = this.getTrackScrollPos();
        const iTo = iFrom + this._maxVisibleTrackNum();
        if (this.logController)
            scrollTracksTo(this.logController, iFrom, iTo);
        if (this.props.onTrackScroll)
            this.props.onTrackScroll();
    }
    onTrackSelection() {
        if (this.props.onTrackSelection)
            this.props.onTrackSelection();
    }
    setInfo(x = Number.NaN) {
        if (!this.props.onInfo)
            return; // no callback is given
        if (!this.logController)
            return; // not initialized yet
        if (isNaN(x) && this.selCurrent !== undefined)
            x = this.selCurrent;
        const iFrom = this.getTrackScrollPos();
        const iTo = iFrom + this._maxVisibleTrackNum();
        this.props.onInfo(x, this.logController, iFrom, iTo);
    }
    onContentRescale() {
        this.showSelection();
        if (this.props.onContentRescale)
            this.props.onContentRescale();
    }
    onContentSelection() {
        this.showSelection();
        if (this.props.onContentSelection)
            this.props.onContentSelection();
    }
    onTrackMouseEvent(ev) {
        if (this.props.onTrackMouseEvent)
            this.props.onTrackMouseEvent(this, ev);
    }
    onTemplateChanged() {
        this.setInfo();
        this.template = this._generateTemplate(); // save current template
        if (this.props.onTemplateChanged)
            this.props.onTemplateChanged();
    }
    // content
    zoomContentTo(domain) {
        if (this.logController)
            return zoomContentTo(this.logController, domain);
        return false;
    }
    scrollContentTo(f) {
        if (this.logController)
            return scrollContentTo(this.logController, f);
        return false;
    }
    zoomContent(zoom) {
        if (this.logController)
            return zoomContent(this.logController, zoom);
        return false;
    }
    showSelection() {
        if (this.logController) {
            const rbelm = this.logController.overlay.elements["rubber-band"];
            const pinelm = this.logController.overlay.elements["pinned"];
            if (rbelm && pinelm) {
                rbelm.style.visibility =
                    this.selCurrent === undefined ? "hidden" : "visible";
                pinelm.style.visibility =
                    this.selPinned === undefined ? "hidden" : "visible";
                showSelection(rbelm, pinelm, this.selCurrent, this.selPinned, this.props.horizontal, this.logController);
            }
        }
    }
    selectContent(selection) {
        this.selCurrent = selection[0];
        this.selPinned = selection[1];
        this.selPersistent = this.selPinned ? true : false;
        this.showSelection();
        this.setInfo(); // reflect new value in this.selCurrent
    }
    setContentBaseDomain(domain) {
        if (this.logController)
            return setContentBaseDomain(this.logController, domain);
    }
    getContentBaseDomain() {
        if (this.logController)
            return getContentBaseDomain(this.logController);
        return [0.0, 0.0];
    }
    getContentDomain() {
        if (this.logController)
            return getContentDomain(this.logController);
        return [0.0, 0.0];
    }
    getContentZoom() {
        if (this.logController)
            return getContentZoom(this.logController);
        return 1.0;
    }
    getContentSelection() {
        if (!this.logController)
            return [undefined, undefined];
        return [this.selCurrent, this.selPinned];
    }
    // tracks
    _graphTrackMax() {
        // for scrollbar
        if (!this.logController)
            return 0;
        const nScaleTracks = getScaleTrackNum(this.logController.tracks);
        return this.logController.tracks.length - nScaleTracks;
    }
    _newTrackScrollPos(pos) {
        let newPos = pos;
        const posMax = this.getTrackScrollPosMax();
        if (newPos > posMax)
            newPos = posMax;
        if (newPos < 0)
            newPos = 0;
        return newPos;
    }
    _maxVisibleTrackNum() {
        return this.props.maxVisibleTrackNum
            ? this.props.maxVisibleTrackNum
            : 5 /*some default value*/;
    }
    scrollTrackBy(delta) {
        this.setState((state) => ({
            scrollTrackPos: this._newTrackScrollPos(state.scrollTrackPos + delta),
        }));
    }
    scrollTrackTo(pos) {
        this.setState((state) => {
            const newPos = this._newTrackScrollPos(pos);
            if (state.scrollTrackPos === newPos) {
                return null;
            }
            return { scrollTrackPos: newPos };
        });
    }
    getTrackScrollPos() {
        return this.state.scrollTrackPos;
    }
    getTrackScrollPosMax() {
        // for scrollbar
        const nGraphTracks = this._graphTrackMax();
        let posMax = nGraphTracks - this._maxVisibleTrackNum();
        if (posMax < 0)
            posMax = 0;
        return posMax;
    }
    getTrackZoom() {
        return this._graphTrackMax() / this._maxVisibleTrackNum();
    }
    getSelectedTrackIndeces() {
        return getSelectedTrackIndeces(this.logController);
    }
    setSelectedTrackIndeces(selection) {
        const changed = setSelectedTrackIndeces(this.logController, selection);
        if (changed)
            this.onTrackSelection();
        return changed;
    }
    getTemplate() {
        return this.template;
    }
    setTemplate(template) {
        const tNew = JSON.stringify(template);
        const t = JSON.stringify(this.template);
        if (t !== tNew) {
            this.template = JSON.parse(tNew); // save external template content to current
            this.setTracks(true);
            /* not sure */ this.onTemplateChanged();
        }
    }
    _generateTemplate() {
        var _a;
        const template = this.template;
        const tracks = [];
        if (this.logController) {
            for (const track of this.logController.tracks) {
                if (isScaleTrack(track))
                    continue;
                const templateTrack = getTrackTemplate(track);
                tracks.push(JSON.parse(JSON.stringify(templateTrack)));
            }
        }
        return {
            name: template.name,
            scale: {
                primary: this.props.primaryAxis,
                allowSecondary: (_a = template.scale) === null || _a === void 0 ? void 0 : _a.allowSecondary,
            },
            tracks: tracks,
            styles: template.styles,
        };
    }
    // editting
    _addTrack(trackCurrent, templateTrack) {
        templateTrack.required = true; // user's tracks could be empty
        const bAfter = true;
        let trackNew;
        if (templateTrack.plots &&
            templateTrack.plots[0] &&
            templateTrack.plots[0].type === "stacked") {
            trackNew = addOrEditStackedTrack(this, null, templateTrack, trackCurrent, bAfter);
        }
        else {
            trackNew = addOrEditGraphTrack(this, null, templateTrack, trackCurrent, bAfter);
        }
        this.onTemplateChanged();
        if (bAfter)
            // force new track to be visible when added after the current
            this.scrollTrackBy(+1);
        else {
            this.onTrackScroll();
            this.setInfo();
        }
        this.selectTrack(trackNew, true);
    }
    _editTrack(track, templateTrack) {
        if (templateTrack.plots && templateTrack.plots[0].type === "stacked") {
            addOrEditStackedTrack(this, track, templateTrack, track, false);
        }
        else {
            addOrEditGraphTrack(this, track, templateTrack, track, false);
        }
        this.onTemplateChanged();
    }
    removeTrack(track) {
        if (this.logController) {
            this.logController.removeTrack(track);
            this.onTrackScroll();
            this.onTrackSelection();
            this.onTemplateChanged();
        }
    }
    isTrackSelected(track) {
        return (!!this.logController && isTrackSelected(this.logController, track));
    }
    selectTrack(track, selected) {
        let changed = false;
        if (this.logController)
            for (const _track of this.logController.tracks) {
                // single selection: remove selection from another tracks
                if (selectTrack(this.logController, _track, selected && track === _track))
                    changed = true;
            }
        if (changed)
            this.onTrackSelection();
        return changed;
    }
    addTrackPlot(track, templatePlot) {
        addOrEditGraphTrackPlot(this, track, null, templatePlot);
        this.onTemplateChanged();
    }
    _editTrackPlot(track, plot, _templatePlot) {
        const templatePlot = Object.assign({}, _templatePlot);
        /* We have special option for track scale!
        const templateTrack = getTrackTemplate(track);
        if (templatePlot.scale === templateTrack.scale)
            templatePlot.scale = undefined;
        */
        addOrEditGraphTrackPlot(this, track, plot, templatePlot);
        this.onTemplateChanged();
    }
    removeTrackPlot(track, plot) {
        removeGraphTrackPlot(this, track, plot);
        const templateTrack = getTrackTemplate(track);
        templateTrack.required = true; // user's tracks could be empty
        this.onTemplateChanged();
    }
    // Dialog functions
    addTrack(parent, trackCurrent) {
        if (parent) {
            addTrack(parent, this, this._addTrack.bind(this, trackCurrent));
        }
    }
    editTrack(parent, track) {
        if (parent) {
            const templateTrack = getTrackTemplate(track);
            editTrack(parent, this, templateTrack, this._editTrack.bind(this, track));
        }
    }
    addPlot(parent, track) {
        if (parent) {
            addPlot(parent, this, track);
        }
    }
    editPlot(parent, track, plot) {
        if (parent) {
            const templateTrack = getTrackTemplate(track);
            const templatePlot = fillPlotTemplate(templateTrack, plot);
            editPlot(parent, this, track, templatePlot, this._editTrackPlot.bind(this, track, plot));
        }
    }
    render() {
        return (React.createElement("div", { style: {
                width: "100%",
                height: "100%",
                display: "flex",
                flexDirection: "column",
            } },
            React.createElement("div", { style: { flex: "1, 1" }, className: "welllogview", ref: (el) => (this.container = el) }),
            this.state.errorText ? (React.createElement("div", { style: { flex: "0, 0" }, className: "welllogview-error" }, this.state.errorText)) : (React.createElement(React.Fragment, null))));
    }
}
export default WellLogView;
//# sourceMappingURL=WellLogView.js.map