# Source: components/data_layer/annotation_track.js

    import BaseDataLayer from './base';
    import {merge} from '../../helpers/layouts';

    /**
     * @memberof module:LocusZoom_DataLayers~annotation_track
     */
    const default_layout = {
        color: '#000000',
        filters: null,
        tooltip_positioning: 'vertical',
        hitarea_width: 8,
    };

    /**
     * Create a single continuous 2D track that provides information about each datapoint
     *
     * For example, this can be used to mark items by membership in a group, alongside information in other panels
     * @alias module:LocusZoom_DataLayers~annotation_track
     * @see {@link module:LocusZoom_DataLayers~BaseDataLayer} for additional layout options
     */
    class AnnotationTrack extends BaseDataLayer {
        /**
         * @param {String|module:LocusZoom_DataLayers~ScalableParameter[]} [layout.color] Specify how to choose the fill color for each tick mark
         * @param {number} [layout.hitarea_width=8] The width (in pixels) of hitareas. Annotation marks are typically 1 px wide,
         *   so a hit area of 4px on each side can make it much easier to select an item for a tooltip. Hitareas will not interfere
         *   with selecting adjacent points.
         * @param {'horizontal'|'vertical'|'top'|'bottom'|'left'|'right'} [layout.tooltip_positioning='vertical'] Where to draw the tooltip relative to the datum.
         */
        constructor(layout) {
            if (!Array.isArray(layout.filters)) {
                throw new Error('Annotation track must specify array of filters for selecting points to annotate');
            }
            merge(layout, default_layout);
            super(...arguments);
        }

        initialize() {
            super.initialize();
            this._hitareas_group = this.svg.group.append('g')
                .attr('class', `lz-data_layer-${this.layout.type}-hit_areas`);

            this._visible_lines_group = this.svg.group.append('g')
                .attr('class', `lz-data_layer-${this.layout.type}-visible_lines`);
        }

        render() {
            // Apply filters to only render a specified set of points
            const track_data = this._applyFilters();

            const hit_areas_selection = this._hitareas_group.selectAll(`rect.lz-data_layer-${this.layout.type}`)
                .data(track_data, (d) => d[this.layout.id_field]);

            const _getX = (d, i) => {
                // Helper for hitarea position calcs: ensures that a hitarea never overlaps the space allocated
                // for a real data element. Helps to avoid mouse jitter when selecting tooltips in crowded areas.
                const x_center = this.parent['x_scale'](d[this.layout.x_axis.field]);
                let x_left = x_center - this.layout.hitarea_width / 2;
                if (i >= 1) {
                    // This assumes that the data are in sorted order.
                    const left_node = track_data[i - 1];
                    const left_node_x_center = this.parent['x_scale'](left_node[this.layout.x_axis.field]);
                    x_left = Math.max(x_left, (x_center + left_node_x_center) / 2);
                }
                return [x_left, x_center];
            };

            // Draw hitareas under real data elements, so that real data elements always take precedence
            hit_areas_selection.enter()
                .append('rect')
                .attr('class', `lz-data_layer-${this.layout.type}`)
                // Update the set of elements to reflect new data
                .merge(hit_areas_selection)
                .attr('id', (d) => this.getElementId(d))
                .attr('height', this.parent.layout.height)
                .attr('opacity', 0)
                .attr('x', (d, i) => {
                    const crds = _getX(d, i);
                    return crds[0];
                })
                .attr('width', (d, i) => {
                    const crds = _getX(d, i);
                    return (crds[1] - crds[0]) + this.layout.hitarea_width / 2;
                });

            const width = 1;
            const selection = this._visible_lines_group.selectAll(`rect.lz-data_layer-${this.layout.type}`)
                .data(track_data, (d) => d[this.layout.id_field]);
            // Draw rectangles (visual and tooltip positioning)
            selection.enter()
                .append('rect')
                .attr('class', `lz-data_layer-${this.layout.type}`)
                .merge(selection)
                .attr('id', (d) => this.getElementId(d))
                .attr('x', (d) => this.parent['x_scale'](d[this.layout.x_axis.field]) - width / 2)
                .attr('width', width)
                .attr('height', this.parent.layout.height)
                .attr('fill', (d, i) => this.resolveScalableParameter(this.layout.color, d, i));

            // Remove unused elements
            selection.exit()
                .remove();

            // Set up tooltips and mouse interaction
            this.svg.group
                .call(this.applyBehaviors.bind(this));

            // Remove unused elements
            hit_areas_selection.exit()
                .remove();
        }

        /**
         * Render tooltip at the center of each tick mark
         * @param tooltip
         * @return {{y_min: number, x_max: *, y_max: *, x_min: number}}
         * @private
         */
        _getTooltipPosition(tooltip) {
            const panel = this.parent;
            const data_layer_height = panel.layout.height - (panel.layout.margin.top + panel.layout.margin.bottom);
            const stroke_width = 1; // as defined in the default stylesheet

            const x_center = panel.x_scale(tooltip.data[this.layout.x_axis.field]);
            const y_center = data_layer_height / 2;
            return {
                x_min: x_center - stroke_width,
                x_max: x_center + stroke_width,
                y_min: y_center - panel.layout.margin.top,
                y_max: y_center + panel.layout.margin.bottom,
            };
        }
    }

    export {AnnotationTrack as default};