/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 COMMON_DB_COMMON_H
#define COMMON_DB_COMMON_H

#include <functional>
#include <iostream>
#include <type_traits>
#include <unordered_set>

#include "common/allocator/my_string.h"
#include "utils/util_define.h"

namespace common {

/**
 * @brief Represents the data type of a measurement.
 *
 * This enumeration defines the supported data types for measurements in the
 * system.
 */
enum TSDataType : uint8_t {
    BOOLEAN = 0,
    INT32 = 1,
    INT64 = 2,
    FLOAT = 3,
    DOUBLE = 4,
    TEXT = 5,
    VECTOR = 6,
    UNKNOWN = 7,
    TIMESTAMP = 8,
    DATE = 9,
    BLOB = 10,
    STRING = 11,
    NULL_TYPE = 254,
    INVALID_DATATYPE = 255
};

/**
 * @brief Represents the encoding method for a measurement.
 *
 * This enumeration defines the supported encoding methods that can be applied
 * to measurements.
 */
enum TSEncoding : uint8_t {
    PLAIN = 0,
    DICTIONARY = 1,
    RLE = 2,
    DIFF = 3,
    TS_2DIFF = 4,
    BITMAP = 5,
    GORILLA_V1 = 6,
    REGULAR = 7,
    GORILLA = 8,
    ZIGZAG = 9,
    FREQ = 10,
    SPRINTZ = 12,
    INVALID_ENCODING = 255
};

/**
 * @brief Represents the compression type for a measurement.
 *
 * This enumeration defines the supported compression methods that can be
 * applied to measurements.
 */
enum CompressionType : uint8_t {
    UNCOMPRESSED = 0,
    SNAPPY = 1,
    GZIP = 2,
    LZO = 3,
    SDT = 4,
    PAA = 5,
    PLA = 6,
    LZ4 = 7,
    INVALID_COMPRESSION = 255
};

extern const char* s_data_type_names[8];
extern const char* s_encoding_names[12];
extern const char* s_compression_names[8];
}  // namespace common

#if defined(__GLIBCXX__) && (__GNUC__ < 7)
namespace std {
template <>
struct hash<common::TSDataType> {
    size_t operator()(common::TSDataType v) const noexcept {
        return static_cast<size_t>(static_cast<uint8_t>(v));
    }
};
}  // namespace std
#endif

namespace common {
FORCE_INLINE const char* get_data_type_name(TSDataType type) {
    ASSERT(type >= BOOLEAN && type <= STRING);
    return s_data_type_names[type];
}

FORCE_INLINE const char* get_encoding_name(TSEncoding encoding) {
    ASSERT(encoding >= PLAIN && encoding <= FREQ);
    return s_encoding_names[encoding];
}

FORCE_INLINE const char* get_compression_name(CompressionType type) {
    return s_compression_names[type];
}

enum Ordering { DESC, ASC };

template <typename T>
FORCE_INLINE common::TSDataType GetDataTypeFromTemplateType() {
    return common::INVALID_DATATYPE;
}

template <>
FORCE_INLINE common::TSDataType GetDataTypeFromTemplateType<bool>() {
    return common::BOOLEAN;
}
template <>
FORCE_INLINE common::TSDataType GetDataTypeFromTemplateType<int32_t>() {
    return common::INT32;
}
template <>
FORCE_INLINE common::TSDataType GetDataTypeFromTemplateType<int64_t>() {
    return common::INT64;
}
template <>
FORCE_INLINE common::TSDataType GetDataTypeFromTemplateType<float>() {
    return common::FLOAT;
}
template <>
FORCE_INLINE common::TSDataType GetDataTypeFromTemplateType<double>() {
    return common::DOUBLE;
}
template <>
FORCE_INLINE common::TSDataType GetDataTypeFromTemplateType<common::String>() {
    return common::STRING;
}

template <typename T>
FORCE_INLINE bool TypeMatch(common::TSDataType dt) {
    return dt == common::INVALID_DATATYPE;
}

template <>
FORCE_INLINE bool TypeMatch<bool>(common::TSDataType dt) {
    return dt == common::BOOLEAN;
}

template <>
FORCE_INLINE bool TypeMatch<int32_t>(common::TSDataType dt) {
    return dt == common::INT32 || dt == common::DATE || dt == common::INT64;
}

template <>
FORCE_INLINE bool TypeMatch<int64_t>(common::TSDataType dt) {
    return dt == common::INT64 || dt == common::TIMESTAMP;
}

template <>
FORCE_INLINE bool TypeMatch<float>(common::TSDataType dt) {
    return dt == common::FLOAT || dt == common::DOUBLE;
}

template <>
FORCE_INLINE bool TypeMatch<double>(common::TSDataType dt) {
    return dt == common::DOUBLE;
}

template <>
FORCE_INLINE bool TypeMatch<common::String>(common::TSDataType dt) {
    return dt == common::STRING || dt == common::TEXT || dt == common::BLOB;
}

FORCE_INLINE size_t get_data_type_size(TSDataType data_type) {
    switch (data_type) {
        case common::BOOLEAN:
            return 1;
        case common::DATE:
        case common::INT32:
        case common::FLOAT:
            return 4;
        case common::INT64:
        case common::TIMESTAMP:
        case common::DOUBLE:
            return 8;
        default:
            ASSERT(false);
            return 8;
    }
}

}  // end namespace common

namespace storage {

struct TimeRange {
    TimeRange() : start_time_(INT64_MAX), end_time_(INT64_MIN) {}
    TimeRange(int64_t start_time, int64_t end_time)
        : start_time_(start_time), end_time_(end_time) {}

    int64_t start_time_;
    int64_t end_time_;
};

}  // namespace storage

#endif
