/*
* Copyright 2023, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and/or binary forms, with or without
* modification, must retain the above copyright notice and the following
* disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
"use strict";
import {Timestamp} from '../proto/google/protobuf/timestamp_pb';
/**
* @typedef {Object} DurationValue
*
* @property {number} seconds
* @property {number} minutes
*/
const NANOSECONDS_IN_MILLISECOND = 1000;
const MILLISECONDS_IN_SECOND = 1000;
const SECONDS_IN_MINUTE = 60;
const MILLISECONDS_IN_MINUTE = SECONDS_IN_MINUTE * MILLISECONDS_IN_SECOND;
const MINUTES_IN_HOUR = 60;
const SECONDS_IN_HOUR = MINUTES_IN_HOUR * SECONDS_IN_MINUTE;
const MILLISECONDS_IN_HOUR = SECONDS_IN_HOUR * MILLISECONDS_IN_SECOND;
const HOURS_IN_DAY = 24;
const MINUTES_IN_DAY = MINUTES_IN_HOUR * HOURS_IN_DAY;
const SECONDS_IN_DAY = MINUTES_IN_DAY * SECONDS_IN_MINUTE;
const MILLISECONDS_IN_DAY = SECONDS_IN_DAY * MILLISECONDS_IN_SECOND;
/**
* Checks that each item in provided items is non-negative. An error is thrown otherwise.
*
* @param {!number[]} items an array of numbers to check
* @param {!String} message a message for when one of the items does not match the requirement
*/
function checkItemsNotNegative(items, message) {
items.forEach(item => {
if (item < 0) {
throw new Error(message);
}
});
}
/**
* Converts a given JavaScript Date into the Timestamp Protobuf message.
*
* @param {!Date} date a date to convert
* @return {Timestamp} a timestamp message of the given date value
*
* @throws error when non-Date value is passed or it is invalid
*/
export function convertDateToTimestamp(date) {
const errorMessage = (message) => `Cannot convert to Timestamp. ${message}`;
if (!(date instanceof Date && typeof date.getTime === 'function')) {
throw new Error(errorMessage(`The given "${date}" isn't of Date type.`));
}
if (isNaN(date.getTime())) {
throw new Error(errorMessage(`The given "${date}" is invalid.`));
}
const millis = date.getTime();
const timestamp = new Timestamp();
timestamp.setSeconds(Math.trunc(millis / 1000));
timestamp.setNanos((millis % 1000) * 1000000);
return timestamp;
}
/**
* A duration of a specified amount of time.
*
* A duration can not be negative, throwing an error if any of the provided values are less than 0.
*/
export class Duration {
/**
* @param {?number} nanoseconds a number of nanoseconds in addition to all other values
* @param {?number} milliseconds a number of milliseconds in addition to all other values
* @param {?number} seconds a number of seconds in addition to all other values
* @param {?number} minutes a number of minutes in addition to all other values
* @param {?number} hours a number of hours in addition to all other values
* @param {?number} days a number of days in addition to all other values
*/
constructor({nanoseconds, milliseconds, seconds, minutes, hours, days}) {
checkItemsNotNegative(
[nanoseconds, milliseconds, seconds, minutes, hours, days],
'Duration cannot be negative'
);
this._nanoseconds = nanoseconds;
this._milliseconds = milliseconds;
this._seconds = seconds;
this._minutes = minutes;
this._hours = hours;
this._days = days;
}
/**
* @return {DurationValue} a value provided to the `Duration` constructor
*/
value() {
return {
nanoseconds: this._nanoseconds,
milliseconds: this._milliseconds,
seconds: this._seconds,
minutes: this._minutes,
hours: this._hours,
days: this._days,
};
}
/**
* @return {number} a total number of ms of this Duration value amounts as an integer
*/
inMs() {
let total = 0;
if (this._nanoseconds) {
total += this._nanoseconds / NANOSECONDS_IN_MILLISECOND;
}
if (this._milliseconds) {
total += this._milliseconds;
}
if (this._seconds) {
total += this._seconds * MILLISECONDS_IN_SECOND;
}
if (this._minutes) {
total += this._minutes * MILLISECONDS_IN_MINUTE;
}
if (this._hours) {
total += this._hours * MILLISECONDS_IN_HOUR;
}
if (this._days) {
total += this._days * MILLISECONDS_IN_DAY;
}
return Math.floor(total);
}
}