import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import debounce from 'debounce';

import IDUtil from '../../../../util/IDUtil';

import Section from './Section';

// Render the given layers with a slight delay, so the UI has time to process the mouse interaction
//
class Layers extends React.Component {
    constructor(props) {
        super(props);

        this.lastUpdate = performance.now();
        this.maxUpdateTime = 250;

        // debounce the performUpdate function
        this.delayedUpdate = debounce(this.performUpdate, this.updateTime);
    }

    performUpdate() {
        this.lastUpdate = performance.now();
        this.forceUpdate();
    }

    shouldComponentUpdate(nextProps) {
        // get variable update time.
        const variableUpdateTime = Math.min(
            this.maxUpdateTime,
            Math.sqrt(nextProps.end - nextProps.start)
        );
        // always render after > variableUpdateTime
        if (performance.now() - this.lastUpdate > variableUpdateTime) {
            this.lastUpdate = performance.now();
            this.delayedUpdate.clear();
            return true;
        } else {
            // delayed update
            this.delayedUpdate();
        }
        return false;
    }

    onSectionClick = (layerId, sectionId, start) => {
        this.props.onSelect(layerId, sectionId);
    };

    render() {
        const {
            layers,
            start,
            end,
            pixelsPerSecond,
            activeLayerId,
            activeSectionId
        } = this.props;

        // Get layers with sections in view

        const durationPadding = (end - start) * 0.03;

        return layers.map(layer => (
            <div
                className={classNames(
                    IDUtil.cssClassName('tl-layer'),
                    layer.className
                )}
                key={layer.id}
                style={{
                    height: layer.height
                }}
                {...layer.extraProps}
            >
                {layer.sections
                    .filter(
                        section =>
                            section.start >
                                start -
                                    (section.end - section.start) -
                                    durationPadding &&
                            section.end <
                                end +
                                    (section.end - section.start) +
                                    durationPadding
                    )
                    .map(section => (
                        <Section
                            key={section.id}
                            sectionId={section.id}
                            layerId={layer.id}
                            start={section.start}
                            active={
                                layer.id === activeLayerId &&
                                section.id === activeSectionId
                            }
                            match={section.match}
                            left={Math.round(
                                section.start > start
                                    ? section.start * pixelsPerSecond
                                    : start * pixelsPerSecond
                            )}
                            width={
                                Math.round(
                                    section.start > start
                                        ? (section.end - section.start) *
                                              pixelsPerSecond
                                        : (section.end -
                                              section.start +
                                              Math.min(
                                                  0,
                                                  section.start - start
                                              )) *
                                              pixelsPerSecond
                                ) + 1 // +1 for filling gaps
                            }
                            onClick={this.onSectionClick}
                        >
                            {section.data}
                        </Section>
                    ))}
            </div>
        ));
    }
}

export const LayersPropTypes = PropTypes.arrayOf(
    PropTypes.shape({
        id: PropTypes.string.isRequired,
        title: PropTypes.string,
        description: PropTypes.string.isRequired,
        extraProps: PropTypes.object,
        sections: PropTypes.arrayOf(
            PropTypes.shape({
                id: PropTypes.string.isRequired,
                start: PropTypes.number.isRequired,
                end: PropTypes.number.isRequired,
                rawData: PropTypes.string,
                data: PropTypes.object
            }).isRequired
        ).isRequired
    }).isRequired
).isRequired;

Layers.propTypes = {
    start: PropTypes.number.isRequired,
    end: PropTypes.number.isRequired,
    pixelsPerSecond: PropTypes.number.isRequired,
    layers: LayersPropTypes,
    searchTerm: PropTypes.string,
    activeLayerId: PropTypes.string,
    activeSectionId: PropTypes.string,
    onSelect: PropTypes.func
};

export default Layers;
