/*
 * Copyright (C) 2014 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 "SplitDescription.h"

#include "aapt/AaptConfig.h"
#include "aapt/AaptUtil.h"

#include <utils/String8.h>
#include <utils/Vector.h>

using namespace android;

namespace split {

SplitDescription::SplitDescription()
: abi(abi::Variant_none) {
}

int SplitDescription::compare(const SplitDescription& rhs) const {
    int cmp;
    cmp = (int)abi - (int)rhs.abi;
    if (cmp != 0) return cmp;
    return config.compareLogical(rhs.config);
}

bool SplitDescription::isBetterThan(const SplitDescription& o, const SplitDescription& target) const {
    if (abi != abi::Variant_none || o.abi != abi::Variant_none) {
        abi::Family family = abi::getFamily(abi);
        abi::Family oFamily = abi::getFamily(o.abi);
        if (family != oFamily) {
            return family != abi::Family_none;
        }

        if (int(target.abi) - int(abi) < int(target.abi) - int(o.abi)) {
            return true;
        }
    }
    return config.isBetterThan(o.config, &target.config);
}

bool SplitDescription::match(const SplitDescription& o) const {
    if (abi != abi::Variant_none) {
        abi::Family family = abi::getFamily(abi);
        abi::Family oFamily = abi::getFamily(o.abi);
        if (family != oFamily) {
            return false;
        }

        if (int(abi) > int(o.abi)) {
            return false;
        }
    }
    return config.match(o.config);
}

String8 SplitDescription::toString() const {
    String8 extension;
    if (abi != abi::Variant_none) {
        if (extension.isEmpty()) {
            extension.append(":");
        } else {
            extension.append("-");
        }
        extension.append(abi::toString(abi));
    }
    String8 str(config.toString());
    str.append(extension);
    return str;
}

ssize_t parseAbi(const Vector<String8>& parts, const ssize_t index,
        SplitDescription* outSplit) {
    const ssize_t N = parts.size();
    abi::Variant abi = abi::Variant_none;
    ssize_t endIndex = index;
    if (parts[endIndex] == "arm64") {
        endIndex++;
        if (endIndex < N) {
            if (parts[endIndex] == "v8a") {
                endIndex++;
                abi = abi::Variant_arm64_v8a;
            }
        }
    } else if (parts[endIndex] == "armeabi") {
        endIndex++;
        abi = abi::Variant_armeabi;
        if (endIndex < N) {
            if (parts[endIndex] == "v7a") {
                endIndex++;
                abi = abi::Variant_armeabi_v7a;
            }
        }
    } else if (parts[endIndex] == "x86") {
        endIndex++;
        abi = abi::Variant_x86;
    } else if (parts[endIndex] == "x86_64") {
        endIndex++;
        abi = abi::Variant_x86_64;
    } else if (parts[endIndex] == "mips") {
        endIndex++;
        abi = abi::Variant_mips;
    } else if (parts[endIndex] == "mips64") {
        endIndex++;
        abi = abi::Variant_mips64;
    }

    if (abi == abi::Variant_none && endIndex != index) {
        return -1;
    }

    if (outSplit != NULL) {
        outSplit->abi = abi;
    }
    return endIndex;
}

bool SplitDescription::parse(const String8& str, SplitDescription* outSplit) {
    ssize_t index = str.find(":");

    String8 configStr;
    String8 extensionStr;
    if (index >= 0) {
        configStr.setTo(str.c_str(), index);
        extensionStr.setTo(str.c_str() + index + 1);
    } else {
        configStr.setTo(str);
    }

    SplitDescription split;
    if (!AaptConfig::parse(configStr, &split.config)) {
        return false;
    }

    Vector<String8> parts = AaptUtil::splitAndLowerCase(extensionStr, '-');
    const ssize_t N = parts.size();
    index = 0;

    if (extensionStr.length() == 0) {
        goto success;
    }

    index = parseAbi(parts, index, &split);
    if (index < 0) {
        return false;
    } else {
        if (index == N) {
            goto success;
        }
    }

    // Unrecognized
    return false;

success:
    if (outSplit != NULL) {
        *outSplit = split;
    }
    return true;
}

} // namespace split
