/*
 * 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 "HidDefs.h"
#include "HidLocal.h"
#include "HidLog.h"
#include <cstddef>

namespace HidUtil {

constexpr uint32_t INVALID_USAGE = 0xFFFF;
constexpr uint32_t INVALID_DESIGNATOR = 0xFFFF;
constexpr uint32_t INVALID_STRING = 0xFFFF;

uint32_t HidLocal::getUsage(size_t index) const {
    if (usage.empty()) {
        return INVALID_USAGE;
    }
    return (index >= usage.size()) ? usage.back() : usage[index];
}

uint32_t HidLocal::getDesignator(size_t index) const {
    if (designator.empty()) {
        return INVALID_DESIGNATOR;
    }
    return (index >= designator.size()) ? designator.back() : designator[index];
}

uint32_t HidLocal::getString(size_t index) const {
    if (string.empty()) {
        return INVALID_STRING;
    }
    return (index >= string.size()) ? string.back() : string[index];
}

void HidLocal::clear() {
    *this = HidLocal();
}

bool HidLocal::append(const HidItem &i) {
    using namespace HidDef::LocalTag;

    bool ret = true;
    unsigned unsignedInteger;
    bool unsignedError = !i.dataAsUnsigned(&unsignedInteger);
    bool valueError = false;

    switch (i.tag) {
        case USAGE:
            usage.push_back(unsignedInteger);
            valueError = unsignedError;
            break;
        case USAGE_MINIMUM:
            usageMin = unsignedInteger;
            valueError = unsignedError;
            break;
        case USAGE_MAXIMUM:
            if (!usageMin.isSet()) {
                LOG_E << "usage min not set when saw usage max " << i << LOG_ENDL;
                ret = false;
            } else {
                uint32_t usagemax = unsignedInteger;
                valueError = unsignedError;
                for (size_t j = usageMin.get(0); j <= usagemax; ++j) {
                    usage.push_back(j);
                }
                usageMin.clear();
            }
            break;
        case STRING_INDEX:
            string.push_back(unsignedInteger);
            valueError = unsignedError;
            break;
        case STRING_MINIMUM:
            stringMin = unsignedInteger;
            valueError = unsignedError;
            break;
        case STRING_MAXIMUM: {
            if (!usageMin.isSet()) {
                LOG_E << "string min not set when saw string max " << i << LOG_ENDL;
                ret = false;
            } else {
                uint32_t stringMax = unsignedInteger;
                valueError = unsignedError;
                for (size_t j = stringMin.get(0); j <= stringMax; ++j) {
                    string.push_back(j);
                }
                stringMin.clear();
            }
            break;
        }
        case DELIMITOR:
            delimeter = unsignedInteger;
            valueError = unsignedError;
            break;
        default:
            LOG_E << "unknown local tag, " << i << LOG_ENDL;
            ret = false;
    }
    if (valueError) {
        LOG_E << "Cannot get unsigned data at " << i << LOG_ENDL;
        ret = false;
    }
    return ret;
}
} //namespace HidUtil