/*
 * 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.
 */

#include "MatrixHal.h"

#include <algorithm>

#include "MapValueIterator.h"

namespace android {
namespace vintf {

bool MatrixHal::operator==(const MatrixHal &other) const {
    if (format != other.format)
        return false;
    if (name != other.name)
        return false;
    if (versionRanges != other.versionRanges)
        return false;
    if (interfaces != other.interfaces)
        return false;
    // do not compare optional
    return true;
}

bool MatrixHal::containsVersion(const Version& version) const {
    for (VersionRange vRange : versionRanges) {
        if (vRange.contains(version)) return true;
    }
    return false;
}

bool MatrixHal::forEachInstance(const std::function<bool(const MatrixInstance&)>& func) const {
    for (const auto& vr : versionRanges) {
        if (!forEachInstance(vr, func)) {
            return false;
        }
    }
    return true;
}

bool MatrixHal::forEachInstance(const VersionRange& vr,
                                const std::function<bool(const MatrixInstance&)>& func) const {
    for (const auto& intf : iterateValues(interfaces)) {
        bool cont =
            intf.forEachInstance([&](const auto& interface, const auto& instance, bool isRegex) {
                // TODO(b/73556059): Store MatrixInstance as well to avoid creating temps
                FqInstance fqInstance;
                if (fqInstance.setTo(getName(), vr.majorVer, vr.minMinor, interface, instance)) {
                    if (!func(MatrixInstance(format, std::move(fqInstance), VersionRange(vr),
                                             optional, isRegex))) {
                        return false;
                    }
                }
                return true;
            });
        if (!cont) {
            return false;
        }
    }
    return true;
}

bool MatrixHal::forEachInstance(
    const std::function<bool(const std::vector<VersionRange>&, const std::string&,
                             const std::string&, bool isRegex)>& func) const {
    for (const auto& intf : iterateValues(interfaces)) {
        bool cont =
            intf.forEachInstance([&](const auto& interface, const auto& instance, bool isRegex) {
                return func(this->versionRanges, interface, instance, isRegex);
            });
        if (!cont) {
            return false;
        }
    }
    return true;
}

bool MatrixHal::isCompatible(const std::set<FqInstance>& providedInstances,
                             const std::set<Version>& providedVersions) const {
    // <version>'s are related by OR.
    return std::any_of(versionRanges.begin(), versionRanges.end(), [&](const VersionRange& vr) {
        return isCompatible(vr, providedInstances, providedVersions);
    });
}

bool MatrixHal::isCompatible(const VersionRange& vr, const std::set<FqInstance>& providedInstances,
                             const std::set<Version>& providedVersions) const {
    bool hasAnyInstance = false;
    bool versionUnsatisfied = false;

    // Look at each interface/instance, and ensure that they are in providedInstances.
    forEachInstance(vr, [&](const MatrixInstance& matrixInstance) {
        hasAnyInstance = true;

        versionUnsatisfied |=
            !std::any_of(providedInstances.begin(), providedInstances.end(),
                         [&](const FqInstance& providedInstance) {
                             return matrixInstance.isSatisfiedBy(providedInstance);
                         });

        return !versionUnsatisfied;  // if any interface/instance is unsatisfied, break
    });

    if (hasAnyInstance) {
        return !versionUnsatisfied;
    }

    // In some cases (e.g. tests and native HALs), compatibility matrix doesn't specify
    // any instances. Check versions only.
    return std::any_of(
        providedVersions.begin(), providedVersions.end(),
        [&](const auto& providedVersion) { return vr.supportedBy(providedVersion); });
}

void MatrixHal::setOptional(bool o) {
    this->optional = o;
}

void MatrixHal::insertVersionRanges(const std::vector<VersionRange>& other) {
    for (const VersionRange& otherVr : other) {
        auto existingVr = std::find_if(this->versionRanges.begin(), this->versionRanges.end(),
                                       [&](const auto& e) { return e.overlaps(otherVr); });

        if (existingVr == this->versionRanges.end()) {
            this->versionRanges.push_back(otherVr);
        } else {
            existingVr->minMinor = std::min(existingVr->minMinor, otherVr.minMinor);
            existingVr->maxMinor = std::max(existingVr->maxMinor, otherVr.maxMinor);
        }
    }
}

void MatrixHal::insertInstance(const std::string& interface, const std::string& instance,
                               bool isRegex) {
    auto it = interfaces.find(interface);
    if (it == interfaces.end())
        it = interfaces.emplace(interface, HalInterface{interface, {}}).first;
    it->second.insertInstance(instance, isRegex);
}

size_t MatrixHal::instancesCount() const {
    size_t count = 0;
    forEachInstance([&](const MatrixInstance&) {
        ++count;
        return true;  // continue;
    });
    return count;
}

bool MatrixHal::removeInstance(const std::string& interface, const std::string& instance,
                               bool isRegex) {
    auto it = interfaces.find(interface);
    if (it == interfaces.end()) return false;
    bool removed = it->second.removeInstance(instance, isRegex);
    if (!it->second.hasAnyInstance()) interfaces.erase(it);
    return removed;
}

void MatrixHal::clearInstances() {
    this->interfaces.clear();
}

} // namespace vintf
} // namespace android
