// Copyright 2019 Google LLC
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef TimeUtils_DEFINED
#define TimeUtils_DEFINED

#include "include/core/SkTypes.h"
#include "include/private/base/SkFloatingPoint.h"

#include <climits>
#include <cmath>

namespace TimeUtils {
// 32 bit value to hold a millisecond duration
using MSec = uint32_t;

// Maximum representable milliseconds; 24d 20h 31m 23.647s
static constexpr MSec MSecMax = INT32_MAX;

// Returns 0 if the timer is stopped. Behavior is undefined if the timer
// has been running longer than MSecMax.
static inline MSec NanosToMSec(double nanos) {
    const double msec = nanos * 1e-6;
    SkASSERT(MSecMax >= msec);
    return static_cast<MSec>(msec);
}

static inline double NanosToSeconds(double nanos) {
    return nanos * 1e-9;
}

// Return the time scaled by "speed" and (if not zero) mod by period.
static inline float Scaled(float time, float speed, float period = 0) {
    double value = time * speed;
    if (period) {
        value = ::fmod(value, (double)(period));
    }
    return (float)value;
}

// Transitions from ends->mid->ends linearly over period time. The phase
// specifies a phase shift in time units.
static inline float PingPong(double time,
                             float period,
                             float phase,
                             float ends,
                             float mid) {
    double value = ::fmod(time + phase, period);
    double half  = period / 2.0;
    double diff  = ::fabs(value - half);
    return (float)(ends + (1.0 - diff / half) * (mid - ends));
}

static inline float SineWave(double time,
                             float periodInSecs,
                             float phaseInSecs,
                             float min,
                             float max) {
    if (periodInSecs < 0.f) {
        return (min + max) / 2.f;
    }
    double t = NanosToSeconds(time) + phaseInSecs;
    t *= 2 * SK_FloatPI / periodInSecs;
    float halfAmplitude = (max - min) / 2.f;
    return halfAmplitude * std::sin(t) + halfAmplitude + min;
}
}  // namespace TimeUtils
#endif
