Source: models/VallisCycle.js

import { fromNow, timeDeltaToString } from 'warframe-worldstate-data/utilities';

import mdConfig from '../supporting/MarkdownSettings.js';

import WorldstateObject from './WorldstateObject.js';

const lStart = new Date('November 10, 2018 08:13:48 UTC');
const loopTime = 1600000;
const warmTime = 400000;
const coldTime = loopTime - warmTime;

/**
 * @typedef {object} CurrentCycle
 * @property {string} state - Current cycle state. One of `warm`, `cold`
 * @property {number} toNextMinor - Time remaining in the current cycle state
 * @property {number} toNextFull - Time remaining until the next cycle
 * @property {Date} timeAtPrevious - Date and time at which the event started
 * @property {Date} timeAtNext - Date and time at which the event start
 */

/**
 * Get the current cycle state for Orb Vallis
 * @returns {CurrentCycle} current cycle state
 */
function getCurrentCycle() {
  const sinceLast = (Date.now() - lStart) % loopTime;
  const toNextFull = loopTime - sinceLast;
  let state = 'cold';
  if (toNextFull > coldTime) {
    state = 'warm';
  }
  let toNextMinor;
  if (toNextFull < coldTime) {
    toNextMinor = toNextFull;
  } else {
    toNextMinor = toNextFull - coldTime;
  }
  const milliAtNext = Date.now() + toNextMinor;
  const milliAtPrev = Date.now() + toNextFull - (state === 'warm' ? loopTime : coldTime);
  const timeAtPrevious = new Date(milliAtPrev);
  timeAtPrevious.setSeconds(0);

  return {
    state,
    toNextMinor,
    toNextFull,
    timeAtNext: new Date(milliAtNext),
    timeAtPrevious,
  };
}

/**
 * Represents the current Earth Day/Night Cycle
 * @augments {WorldstateObject}
 */
export default class VallisCycle extends WorldstateObject {
  /**
   * The current cetus cycle, for calculating the other fields
   * @property {string} state - Current cycle state. One of `warm`, `cold`
   * @property {number} toNextMinor - Time remaining in the current cycle state
   * @property {number} toNextFull - Time remaining until the next cycle
   * @property {Date} timeAtPrevious - Date and time at which the event started
   * @private
   */
  #ec = getCurrentCycle();

  constructor() {
    super({ _id: { $oid: 'vallisCycle0' } });

    /**
     * The date and time at which the event ends
     * @type {Date}
     */
    this.expiry = this.#ec.timeAtNext;

    /**
     * Whether or not this it's daytime
     * @type {boolean}
     */
    this.isWarm = this.#ec.state === 'warm';

    /**
     * Current cycle state. One of `warm`, `cold`
     * @type {string}
     */
    this.state = this.#ec.state;

    /**
     * Date and time at which the event started
     * @type {Date}
     */
    this.activation = this.#ec.timeAtPrevious;

    /**
     * Time remaining string
     * @type {string}
     */
    this.timeLeft = timeDeltaToString(this.#ec.toNextMinor);

    this.id = `vallisCycle${this.#ec.timeAtPrevious.getTime()}`;

    this.shortString = `${this.timeLeft.replace(/\s\d*s/gi, '')} to ${this.isWarm ? 'Cold' : 'Warm'}`;
  }

  /**
   * Get whether or not the event has expired
   * @returns {boolean} whether this event has expired
   */
  getExpired() {
    return fromNow(this.expiry) < 0;
  }

  /**
   * The event's string representation
   * @returns {string} the event's string representation
   */
  toString() {
    const lines = [
      `Operator, the Orb Vallis is currently ${this.isWarm ? 'Warm' : 'Cold'}`,
      `Time remaining until ${this.isWarm ? 'Cold' : 'Warm'}: ${this.timeLeft}`,
    ];

    return lines.join(mdConfig.lineEnd);
  }
}