'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.CountdownNotifierLabel = exports.CountdownTimer = undefined;

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

var _reactBootstrap = require('react-bootstrap');

var _tools = require('views/utils/tools');

var _notifiers = require('views/utils/notifiers');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

class Ticker {
  constructor() {
    this.tick = () => {
      const now = Date.now();
      this.callbacks.forEach(f => f(now));
    };

    this.count = () => {
      if (!this.counting) {
        return;
      }
      this.tick();
      setTimeout(this.count, 1000);
    };

    this.start = () => {
      this.counting = true;
      this.count();
    };

    this.stop = () => {
      this.counting = false;
    };

    this.reg = (key, func) => {
      this.callbacks.set(key, func);
      if (!this.counting) {
        this.start();
      }
    };

    this.unreg = key => {
      this.callbacks.delete(key);
      if (this.callbacks.size === 0) {
        this.stop();
      }
    };

    this.counting = false;
    this.callbacks = new Map();
  }
}

window.ticker = new Ticker();

class CountdownTimer extends _react.Component {
  constructor(props) {
    super(props);
    this.defaultProps = {
      completeTime: -1,
      tickCallback: null,
      completeCallback: null
    };
    this.state = {
      completeTime: this.props.completeTime
    };

    this.componentDidMount = () => {
      this.startTick();
      window.addEventListener('countdown.start', this.startTick);
      window.addEventListener('countdown.stop', this.stopTick);
    };

    this.componentWillReceiveProps = nextProps => {
      if (nextProps.countdownId !== this.props.countdownId) {
        this.stopTick();
      }
      if (nextProps.completeTime !== this.state.completeTime) {
        this.setState({ completeTime: nextProps.completeTime });
        this.timeRemaining = this.constructor.getTimeRemaining(nextProps.completeTime);
      }
    };

    this.shouldComponentUpdate = (nextProps, nextState) => nextProps.countdownId !== this.props.countdownId || nextState.completeTime !== this.state.completeTime;

    this.componentDidUpdate = () => {
      this.startTick // Doesn't matter if it didn't stop
      ();
    };

    this.componentWillUnmount = () => {
      this.stopTick();
      window.removeEventListener('countdown.start', this.startTick);
      window.removeEventListener('countdown.stop', this.stopTick);
    };

    this.startTick = () => {
      window.ticker.reg(this.props.countdownId, this.tick);
    };

    this.stopTick = () => {
      window.ticker.unreg(this.props.countdownId);
    };

    this.tick = currentTime => {
      const actualRemaining = this.constructor.getTimeRemaining(this.state.completeTime, currentTime);
      if (Math.abs(this.timeRemaining - actualRemaining) > 2) {
        this.timeRemaining = actualRemaining;
      }
      this.timeRemaining = this.constructor.getTimeRemaining(this.state.completeTime, currentTime);
      if (this.timeRemaining < 1) {
        this.stopTick();
      }
      if (this.state.completeTime >= 0) try {
        if (this.textLabel) {
          this.textLabel.textContent = this.resolveTime(this.timeRemaining);
        }
        if (this.props.tickCallback) {
          this.props.tickCallback(this.timeRemaining);
        }
        if (this.timeRemaining < 1 && this.props.completeCallback) {
          this.props.completeCallback();
        }
      } catch (error) {
        console.error(error.stack);
      }
      this.timeRemaining--;
    };

    this.timeRemaining = this.constructor.getTimeRemaining(this.props.completeTime);
    this.resolveTime = props.resolveTime || _tools.resolveTime;
  }

  render() {
    return _react2.default.createElement(
      'span',
      { ref: ref => {
          this.textLabel = ref;
        } },
      this.resolveTime(this.timeRemaining)
    );
  }
}

exports.CountdownTimer = CountdownTimer;

CountdownTimer.getTimeRemaining = (completeTime, currentTime = Date.now()) => {
  if (completeTime < 0) {
    return -1;
  } else if (completeTime <= currentTime) {
    return 0;
  } else {
    return Math.round((completeTime - currentTime) / 1000);
  }
};

CountdownTimer.propTypes = {
  countdownId: _propTypes2.default.string.isRequired,
  completeTime: _propTypes2.default.number,
  tickCallback: _propTypes2.default.func,
  completeCallback: _propTypes2.default.func
};
class CountdownNotifierLabel extends _react.Component {
  constructor(props) {
    super(props);

    _initialiseProps.call(this);

    this.notifier = new _notifiers.CountdownNotifier();
    this.state = {
      style: this.getLabelStyle(props)
    };
  }
  componentWillReceiveProps(nextProps) {
    if (nextProps.completeTime != this.props.completeTime) {
      this.setState({
        style: this.getLabelStyle(nextProps)
      });
    }
  }
  shouldComponentUpdate(nextProps, nextState) {
    return nextProps.completeTime !== this.props.completeTime || nextState.style !== this.state.style;
  }

  render() {
    return _react2.default.createElement(
      _reactBootstrap.Label,
      { className: 'countdown-timer-label', bsStyle: this.state.style },
      this.props.completeTime >= 0 && _react2.default.createElement(CountdownTimer, { countdownId: this.props.timerKey,
        completeTime: this.props.completeTime,
        tickCallback: this.tick,
        resolveTime: this.props.resolveTime })
    );
  }
}
exports.CountdownNotifierLabel = CountdownNotifierLabel;
CountdownNotifierLabel.propTypes = {
  timerKey: _propTypes2.default.string.isRequired, // A globally unique string for the timer
  completeTime: _propTypes2.default.number.isRequired,
  getNotifyOptions: _propTypes2.default.func, // (props, timeRemaining) => options | undefined
  getLabelStyle: _propTypes2.default.func, // (props, timeRemaining) => bsStyle
  resolveTime: _propTypes2.default.func // (timeRemaining) => interpreted time string
};
CountdownNotifierLabel.defaultProps = {
  getNotifyOptions: () => undefined,
  getLabelStyle: () => 'default',
  resolveTime: _tools.resolveTime
};

var _initialiseProps = function () {
  this.getLabelStyle = props => {
    return props.getLabelStyle(props, CountdownTimer.getTimeRemaining(props.completeTime));
  };

  this.tick = timeRemaining => {
    const notifyOptions = this.props.getNotifyOptions(this.props);
    if (notifyOptions) this.notifier.tryNotify(notifyOptions);
    const style = this.getLabelStyle(this.props);
    if (style !== this.state.style) this.setState({ style: style });
  };
};