/*
 * 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 ANDROID_VINTF_VERSION_H
#define ANDROID_VINTF_VERSION_H

#include <stdint.h>
#include <optional>
#include <string>
#include <utility>

namespace android {
namespace vintf {

struct Version {

    constexpr Version() : Version(0u, 0u) {}
    constexpr Version(size_t mj, size_t mi) : majorVer(mj), minorVer(mi) {}
    constexpr Version(const std::pair<size_t, size_t>& pair)
        : majorVer(pair.first), minorVer(pair.second) {}

    size_t majorVer;
    size_t minorVer;

    inline bool operator==(const Version &other) const {
        return majorVer == other.majorVer && minorVer == other.minorVer;
    }
    inline bool operator!=(const Version &other) const {
        return !((*this) == other);
    }
    inline bool operator<(const Version &other) const {
        if (majorVer < other.majorVer)
            return true;
        if (majorVer > other.majorVer)
            return false;
        return minorVer < other.minorVer;
    }
    inline bool operator>(const Version &other) const {
        return other < (*this);
    }
    inline bool operator<=(const Version &other) const {
        return !((*this) > other);
    }
    inline bool operator>=(const Version &other) const {
        return !((*this) < other);
    }
    // Version(2, 1).minorAtLeast(Version(1, 0)) == false
    // Version(2, 1).minorAtLeast(Version(2, 0)) == true
    // Version(2, 1).minorAtLeast(Version(2, 1)) == true
    // Version(2, 1).minorAtLeast(Version(2, 2)) == false
    inline bool minorAtLeast(const Version& other) const {
        return majorVer == other.majorVer && minorVer >= other.minorVer;
    }

    inline Version withMinor(size_t mi) { return Version(majorVer, mi); }
};

struct SepolicyVersion {
    constexpr SepolicyVersion() : SepolicyVersion(0u, std::nullopt) {}
    constexpr SepolicyVersion(size_t mj, std::optional<size_t> mi) : majorVer(mj), minorVer(mi) {}

    size_t majorVer;
    std::optional<size_t> minorVer;

    bool operator==(const SepolicyVersion& other) const = default;
    bool operator!=(const SepolicyVersion& other) const = default;
    inline bool operator<(const SepolicyVersion& other) const {
        return std::pair(majorVer, minorVer) < std::pair(other.majorVer, other.minorVer);
    }
    inline bool operator>(const SepolicyVersion& other) const { return other < *this; }
    inline bool operator<=(const SepolicyVersion& other) const { return !((*this) > other); }
    inline bool operator>=(const SepolicyVersion& other) const { return !((*this) < other); }
};

struct KernelVersion {

    constexpr KernelVersion() : KernelVersion(0u, 0u, 0u) {}
    constexpr KernelVersion(size_t v, size_t mj, size_t mi) :
            version(v), majorRev(mj), minorRev(mi) {}

    size_t version;
    size_t majorRev;
    size_t minorRev;

    inline bool operator==(const KernelVersion &other) const {
        return version == other.version
            && majorRev == other.majorRev
            && minorRev == other.minorRev;
    }
    inline bool operator!=(const KernelVersion &other) const {
        return !((*this) == other);
    }

    inline bool operator<(const KernelVersion& other) const {
        if (version < other.version) return true;
        if (version > other.version) return false;
        if (majorRev < other.majorRev) return true;
        if (majorRev > other.majorRev) return false;
        return minorRev < other.minorRev;
    }
    inline bool operator>(const KernelVersion& other) const { return other < (*this); }
    inline bool operator<=(const KernelVersion& other) const { return !((*this) > other); }
    inline bool operator>=(const KernelVersion& other) const { return !((*this) < other); }

    inline constexpr Version dropMinor() const { return Version{version, majorRev}; }
};

} // namespace vintf
} // namespace android

#endif // ANDROID_VINTF_VERSION_H
