/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * 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
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef CHRE_UTIL_TIME_IMPL_H_
#define CHRE_UTIL_TIME_IMPL_H_

#include "chre/util/time.h"

namespace chre {

constexpr Seconds::Seconds(uint64_t seconds) : mSeconds(seconds) {}

constexpr uint64_t Seconds::toRawNanoseconds() const {
  // Perform the simple unit conversion. Warning: overflow is caught and
  // handled by returning UINT64_MAX. A ternary expression is used because
  // constexpr requires it.
  return (mSeconds > (UINT64_MAX / kOneSecondInNanoseconds))
             ? UINT64_MAX
             : mSeconds * kOneSecondInNanoseconds;
}

constexpr uint64_t Seconds::getMilliseconds() const {
  // Perform the simple unit conversion. Warning: overflow is caught and
  // handled by returning UINT64_MAX. A ternary expression is used because
  // constexpr requires it.
  return (mSeconds > (UINT64_MAX / kOneSecondInMilliseconds))
             ? UINT64_MAX
             : mSeconds * kOneSecondInMilliseconds;
}

constexpr Milliseconds::Milliseconds() : mMilliseconds(0) {}

constexpr Milliseconds::Milliseconds(uint64_t milliseconds)
    : mMilliseconds(milliseconds) {}

constexpr Milliseconds::Milliseconds(Nanoseconds nanoseconds)
    : mMilliseconds(nanoseconds.toRawNanoseconds() /
                    kOneMillisecondInNanoseconds) {}

constexpr uint64_t Milliseconds::toRawNanoseconds() const {
  // Perform the simple unit conversion. Warning: overflow is caught and
  // handled by returning UINT64_MAX. A ternary expression is used because
  // constexpr requires it.
  return (mMilliseconds > (UINT64_MAX / kOneMillisecondInNanoseconds))
             ? UINT64_MAX
             : mMilliseconds * kOneMillisecondInNanoseconds;
}

constexpr uint64_t Milliseconds::getMicroseconds() const {
  // Perform the simple unit conversion. Warning: overflow is caught and
  // handled by returning UINT64_MAX. A ternary expression is used because
  // constexpr requires it.
  return (mMilliseconds > (UINT64_MAX / kOneMillisecondInMicroseconds))
             ? UINT64_MAX
             : mMilliseconds * kOneMillisecondInMicroseconds;
}

constexpr uint64_t Milliseconds::getMilliseconds() const {
  return mMilliseconds;
}

constexpr bool Milliseconds::operator==(const Milliseconds &millis) const {
  return (mMilliseconds == millis.mMilliseconds);
}

constexpr Microseconds::Microseconds(uint64_t microseconds)
    : mMicroseconds(microseconds) {}

constexpr Microseconds::Microseconds(Nanoseconds nanoseconds)
    : mMicroseconds(nanoseconds.toRawNanoseconds() /
                    kOneMicrosecondInNanoseconds) {}

constexpr uint64_t Microseconds::toRawNanoseconds() const {
  // Perform the simple unit conversion. Warning: overflow is caught and
  // handled by returning UINT64_MAX. A ternary expression is used because
  // constexpr requires it.
  return (mMicroseconds > (UINT64_MAX / kOneMicrosecondInNanoseconds))
             ? UINT64_MAX
             : mMicroseconds * kOneMicrosecondInNanoseconds;
}

constexpr uint64_t Microseconds::getMicroseconds() const {
  return mMicroseconds;
}

constexpr uint64_t Microseconds::getMilliseconds() const {
  return (mMicroseconds / kOneMillisecondInMicroseconds);
}

constexpr Nanoseconds::Nanoseconds() : mNanoseconds(0) {}

constexpr Nanoseconds::Nanoseconds(uint64_t nanoseconds)
    : mNanoseconds(nanoseconds) {}

constexpr Nanoseconds::Nanoseconds(Seconds seconds)
    : mNanoseconds(seconds.toRawNanoseconds()) {}

constexpr Nanoseconds::Nanoseconds(Milliseconds milliseconds)
    : mNanoseconds(milliseconds.toRawNanoseconds()) {}

constexpr Nanoseconds::Nanoseconds(Microseconds microseconds)
    : mNanoseconds(microseconds.toRawNanoseconds()) {}

constexpr uint64_t Nanoseconds::toRawNanoseconds() const {
  return mNanoseconds;
}

constexpr bool Nanoseconds::operator==(const Nanoseconds &nanos) const {
  return (mNanoseconds == nanos.mNanoseconds);
}

constexpr bool Nanoseconds::operator!=(const Nanoseconds &nanos) const {
  return !(mNanoseconds == nanos.mNanoseconds);
}

constexpr Nanoseconds operator+(const Seconds &secs, const Nanoseconds &nanos) {
  return Nanoseconds(secs.toRawNanoseconds() + nanos.toRawNanoseconds());
}

constexpr Nanoseconds operator+(const Nanoseconds &nanos_a,
                                const Nanoseconds &nanos_b) {
  return Nanoseconds(nanos_a.toRawNanoseconds() + nanos_b.toRawNanoseconds());
}

constexpr Nanoseconds operator-(const Nanoseconds &nanos_a,
                                const Nanoseconds &nanos_b) {
  return Nanoseconds(nanos_a.toRawNanoseconds() - nanos_b.toRawNanoseconds());
}

constexpr Nanoseconds operator*(const Nanoseconds &nanos, uint64_t multiplier) {
  return Nanoseconds(nanos.toRawNanoseconds() * multiplier);
}

constexpr bool operator>=(const Nanoseconds &nanos_a,
                          const Nanoseconds &nanos_b) {
  return nanos_a.toRawNanoseconds() >= nanos_b.toRawNanoseconds();
}

constexpr bool operator<=(const Nanoseconds &nanos_a,
                          const Nanoseconds &nanos_b) {
  return nanos_a.toRawNanoseconds() <= nanos_b.toRawNanoseconds();
}

constexpr bool operator<(const Nanoseconds &nanos_a,
                         const Nanoseconds &nanos_b) {
  return nanos_a.toRawNanoseconds() < nanos_b.toRawNanoseconds();
}

constexpr bool operator>(const Nanoseconds &nanos_a,
                         const Nanoseconds &nanos_b) {
  return nanos_a.toRawNanoseconds() > nanos_b.toRawNanoseconds();
}

}  // namespace chre

#endif  // CHRE_UTIL_TIME_IMPL_H_
