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

#include "runtime/raw_value.h"
#include "util/types.h"

namespace doris {

int RawValue::compare(const void* v1, const void* v2, const TypeDescriptor& type) {
    const StringValue* string_value1;
    const StringValue* string_value2;
    const DateTimeValue* ts_value1;
    const DateTimeValue* ts_value2;
    const DecimalValue* decimal_value1;
    const DecimalValue* decimal_value2;
    float f1 = 0;
    float f2 = 0;
    double d1 = 0;
    double d2 = 0;
    int32_t i1;
    int32_t i2;
    int64_t b1;
    int64_t b2;

    if (NULL == v1 && NULL == v2) {
        return 0;
    } else if (NULL == v1 && NULL != v2) {
        return -1;
    } else if (NULL != v1 && NULL == v2) {
        return 1;
    }

    switch (type.type) {
    case TYPE_NULL:
        return 0;

    case TYPE_BOOLEAN:
        return *reinterpret_cast<const bool*>(v1) - *reinterpret_cast<const bool*>(v2);

    case TYPE_TINYINT:
        return *reinterpret_cast<const int8_t*>(v1) - *reinterpret_cast<const int8_t*>(v2);

    case TYPE_SMALLINT:
        return *reinterpret_cast<const int16_t*>(v1) -
               *reinterpret_cast<const int16_t*>(v2);

    case TYPE_INT:
        i1 = *reinterpret_cast<const int32_t*>(v1);
        i2 = *reinterpret_cast<const int32_t*>(v2);
        return i1 > i2 ? 1 : (i1 < i2 ? -1 : 0);

    case TYPE_BIGINT:
        b1 = *reinterpret_cast<const int64_t*>(v1);
        b2 = *reinterpret_cast<const int64_t*>(v2);
        return b1 > b2 ? 1 : (b1 < b2 ? -1 : 0);

    case TYPE_FLOAT:
        // TODO: can this be faster? (just returning the difference has underflow problems)
        f1 = *reinterpret_cast<const float*>(v1);
        f2 = *reinterpret_cast<const float*>(v2);
        return f1 > f2 ? 1 : (f1 < f2 ? -1 : 0);

    case TYPE_DOUBLE:
        // TODO: can this be faster?
        d1 = *reinterpret_cast<const double*>(v1);
        d2 = *reinterpret_cast<const double*>(v2);
        return d1 > d2 ? 1 : (d1 < d2 ? -1 : 0);

    case TYPE_CHAR:
    case TYPE_VARCHAR:
    case TYPE_HLL: 
        string_value1 = reinterpret_cast<const StringValue*>(v1);
        string_value2 = reinterpret_cast<const StringValue*>(v2);
        return string_value1->compare(*string_value2);

    case TYPE_DATE:
    case TYPE_DATETIME:
        ts_value1 = reinterpret_cast<const DateTimeValue*>(v1);
        ts_value2 = reinterpret_cast<const DateTimeValue*>(v2);
        return *ts_value1 > *ts_value2 ? 1 : (*ts_value1 < *ts_value2 ? -1 : 0);

    case TYPE_DECIMAL:
        decimal_value1 = reinterpret_cast<const DecimalValue*>(v1);
        decimal_value2 = reinterpret_cast<const DecimalValue*>(v2);
        return (*decimal_value1 > *decimal_value2)
                ? 1 : (*decimal_value1 < *decimal_value2 ? -1 : 0);

    case TYPE_LARGEINT: {
        __int128 large_int_value1 = reinterpret_cast<const PackedInt128*>(v1)->value;
        __int128 large_int_value2 = reinterpret_cast<const PackedInt128*>(v2)->value;
        return large_int_value1 > large_int_value2 ? 1 : 
                (large_int_value1 < large_int_value2 ? -1 : 0);
    }

    default:
        DCHECK(false) << "invalid type: " << type.type;
        return 0;
    };
}

}
