/*!The Treasure Box Library
 *
 * 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.
 *
 * Copyright (C) 2009-present, TBOOX Open Source Group.
 *
 * @author      ruki
 * @file        value.h
 * @ingroup     database
 *
 */
#ifndef TB_DATABASE_SQL_VALUE_H
#define TB_DATABASE_SQL_VALUE_H

/* //////////////////////////////////////////////////////////////////////////////////////
 * includes
 */
#include "prefix.h"
#include "../stream/stream.h"

/* //////////////////////////////////////////////////////////////////////////////////////
 * extern
 */
__tb_extern_c_enter__

/* //////////////////////////////////////////////////////////////////////////////////////
 * types
 */

/// the sql database value type enum
typedef enum __tb_database_sql_value_type_e
{
    TB_DATABASE_SQL_VALUE_TYPE_NULL         = 0
,   TB_DATABASE_SQL_VALUE_TYPE_INT8         = 1
,   TB_DATABASE_SQL_VALUE_TYPE_INT16        = 2
,   TB_DATABASE_SQL_VALUE_TYPE_INT32        = 3
,   TB_DATABASE_SQL_VALUE_TYPE_INT64        = 4
,   TB_DATABASE_SQL_VALUE_TYPE_UINT8        = 5
,   TB_DATABASE_SQL_VALUE_TYPE_UINT16       = 6
,   TB_DATABASE_SQL_VALUE_TYPE_UINT32       = 7
,   TB_DATABASE_SQL_VALUE_TYPE_UINT64       = 8
#ifdef TB_CONFIG_TYPE_HAVE_FLOAT
,   TB_DATABASE_SQL_VALUE_TYPE_FLOAT        = 13
,   TB_DATABASE_SQL_VALUE_TYPE_DOUBLE       = 14
#endif
,   TB_DATABASE_SQL_VALUE_TYPE_BLOB8        = 9
,   TB_DATABASE_SQL_VALUE_TYPE_BLOB16       = 10
,   TB_DATABASE_SQL_VALUE_TYPE_BLOB32       = 11
,   TB_DATABASE_SQL_VALUE_TYPE_TEXT         = 12

}tb_database_sql_value_type_e;

/// the sql database value type
typedef struct __tb_database_sql_value_t
{
    /// the type
    tb_size_t                   type;

    /// the name
    tb_char_t const*            name;

    /// the data
    union
    {
        // int
        tb_int8_t               i8;
        tb_int16_t              i16;
        tb_int32_t              i32;
        tb_int64_t              i64;

        // uint
        tb_uint8_t              u8;
        tb_uint16_t             u16;
        tb_uint32_t             u32;
        tb_uint64_t             u64;

        // float
#ifdef TB_CONFIG_TYPE_HAVE_FLOAT
        tb_float_t              f;
        tb_double_t             d;
#endif

        // blob
        struct
        {
            tb_byte_t const*    data;
            tb_size_t           size;

            // the stream for blob32
            tb_stream_ref_t  stream;

        }                       blob;

        // text
        struct
        {
            tb_char_t const*    data;
            tb_size_t           hint;

        }                       text;

    }u;

}tb_database_sql_value_t;

/* //////////////////////////////////////////////////////////////////////////////////////
 * interfaces
 */

/*! the value data size
 *
 * @param value     the value
 *
 * @return          the value data size
 */
tb_size_t           tb_database_sql_value_size(tb_database_sql_value_t const* value);

/*! the int8 value
 *
 * @param value     the value
 *
 * @return          the int8 value
 */
tb_int8_t           tb_database_sql_value_int8(tb_database_sql_value_t const* value);

/*! the int16 value
 *
 * @param value     the value
 *
 * @return          the int16 value
 */
tb_int16_t          tb_database_sql_value_int16(tb_database_sql_value_t const* value);

/*! the int32 value
 *
 * @param value     the value
 *
 * @return          the int32 value
 */
tb_int32_t          tb_database_sql_value_int32(tb_database_sql_value_t const* value);

/*! the int64 value
 *
 * @param value     the value
 *
 * @return          the int64 value
 */
tb_int64_t          tb_database_sql_value_int64(tb_database_sql_value_t const* value);

/*! the uint8 value
 *
 * @param value     the value
 *
 * @return          the uint8 value
 */
tb_uint8_t          tb_database_sql_value_uint8(tb_database_sql_value_t const* value);

/*! the uint16 value
 *
 * @param value     the value
 *
 * @return          the uint16 value
 */
tb_uint16_t         tb_database_sql_value_uint16(tb_database_sql_value_t const* value);

/*! the uint32 value
 *
 * @param value     the value
 *
 * @return          the uint32 value
 */
tb_uint32_t         tb_database_sql_value_uint32(tb_database_sql_value_t const* value);

/*! the uint64 value
 *
 * @param value     the value
 *
 * @return          the uint64 value
 */
tb_uint64_t         tb_database_sql_value_uint64(tb_database_sql_value_t const* value);

#ifdef TB_CONFIG_TYPE_HAVE_FLOAT
/*! the float value
 *
 * @param value     the value
 *
 * @return          the float value
 */
tb_float_t          tb_database_sql_value_float(tb_database_sql_value_t const* value);

/*! the double value
 *
 * @param value     the value
 *
 * @return          the double value
 */
tb_double_t         tb_database_sql_value_double(tb_database_sql_value_t const* value);
#endif

/*! set the null value
 *
 * @param value     the value
 */
tb_void_t           tb_database_sql_value_set_null(tb_database_sql_value_t* value);

/*! set the int8 value
 *
 * @param value     the value
 * @param number    the number
 */
tb_void_t           tb_database_sql_value_set_int8(tb_database_sql_value_t* value, tb_int8_t number);

/*! set the int16 value
 *
 * @param value     the value
 * @param number    the number
 */
tb_void_t           tb_database_sql_value_set_int16(tb_database_sql_value_t* value, tb_int16_t number);

/*! set the int32 value
 *
 * @param value     the value
 * @param number    the number
 */
tb_void_t           tb_database_sql_value_set_int32(tb_database_sql_value_t* value, tb_int32_t number);

/*! set the int64 value
 *
 * @param value     the value
 * @param number    the number
 */
tb_void_t           tb_database_sql_value_set_int64(tb_database_sql_value_t* value, tb_int64_t number);

/*! set the uint8 value
 *
 * @param value     the value
 * @param number    the number
 */
tb_void_t           tb_database_sql_value_set_uint8(tb_database_sql_value_t* value, tb_uint8_t number);

/*! set the uint16 value
 *
 * @param value     the value
 * @param number    the number
 */
tb_void_t           tb_database_sql_value_set_uint16(tb_database_sql_value_t* value, tb_uint16_t number);

/*! set the uint32 value
 *
 * @param value     the value
 * @param number    the number
 */
tb_void_t           tb_database_sql_value_set_uint32(tb_database_sql_value_t* value, tb_uint32_t number);

/*! set the uint64 value
 *
 * @param value     the value
 * @param number    the number
 */
tb_void_t           tb_database_sql_value_set_uint64(tb_database_sql_value_t* value, tb_uint64_t number);

#ifdef TB_CONFIG_TYPE_HAVE_FLOAT
/*! set the float value
 *
 * @param value     the value
 * @param number    the number
 */
tb_void_t           tb_database_sql_value_set_float(tb_database_sql_value_t* value, tb_float_t number);

/*! set the double value
 *
 * @param value     the value
 * @param number    the number
 */
tb_void_t           tb_database_sql_value_set_double(tb_database_sql_value_t* value, tb_double_t number);
#endif

/*! set the text value
 *
 * @param value     the value
 * @param text      the text data
 * @param hint      the text size hint
 */
tb_void_t           tb_database_sql_value_set_text(tb_database_sql_value_t* value, tb_char_t const* text, tb_size_t hint);

/*! set the blob8 value
 *
 * @param value     the value
 * @param data      the blob data
 * @param size      the blob size
 */
tb_void_t           tb_database_sql_value_set_blob8(tb_database_sql_value_t* value, tb_byte_t const* data, tb_size_t size);

/*! set the blob16 value
 *
 * @param value     the value
 * @param data      the blob data
 * @param size      the blob size
 */
tb_void_t           tb_database_sql_value_set_blob16(tb_database_sql_value_t* value, tb_byte_t const* data, tb_size_t size);

/*! set the blob32 value
 *
 * @param value     the value
 * @param data      the blob data
 * @param size      the blob size
 * @param stream    the stream, using it if data == null
 */
tb_void_t           tb_database_sql_value_set_blob32(tb_database_sql_value_t* value, tb_byte_t const* data, tb_size_t size, tb_stream_ref_t stream);

/* //////////////////////////////////////////////////////////////////////////////////////
 * inlines
 */

/// the value is null?
static __tb_inline_force__ tb_bool_t tb_database_sql_value_is_null(tb_database_sql_value_t const* value)
{
    return (value && value->type == TB_DATABASE_SQL_VALUE_TYPE_NULL)? tb_true : tb_false;
}

/// the value is text?
static __tb_inline_force__ tb_bool_t tb_database_sql_value_is_text(tb_database_sql_value_t const* value)
{
    return (value && value->type == TB_DATABASE_SQL_VALUE_TYPE_TEXT)? tb_true : tb_false;
}

/// the value is blob?
static __tb_inline_force__ tb_bool_t tb_database_sql_value_is_blob(tb_database_sql_value_t const* value)
{
    return (    value
            &&  (   value->type == TB_DATABASE_SQL_VALUE_TYPE_BLOB32
                ||  value->type == TB_DATABASE_SQL_VALUE_TYPE_BLOB16
                ||  value->type == TB_DATABASE_SQL_VALUE_TYPE_BLOB8))? tb_true : tb_false;
}

/// the value is blob32?
static __tb_inline_force__ tb_bool_t tb_database_sql_value_is_blob32(tb_database_sql_value_t const* value)
{
    return (value && value->type == TB_DATABASE_SQL_VALUE_TYPE_BLOB32)? tb_true : tb_false;
}
/// the value is integer?
static __tb_inline_force__ tb_bool_t tb_database_sql_value_is_integer(tb_database_sql_value_t const* value)
{
    return (value && value->type >= TB_DATABASE_SQL_VALUE_TYPE_INT8 && value->type <= TB_DATABASE_SQL_VALUE_TYPE_UINT64)? tb_true : tb_false;
}

/// the value is float?
#ifdef TB_CONFIG_TYPE_HAVE_FLOAT
static __tb_inline_force__ tb_bool_t tb_database_sql_value_is_float(tb_database_sql_value_t const* value)
{
    return (    value
            &&  (   value->type == TB_DATABASE_SQL_VALUE_TYPE_FLOAT
                ||  value->type == TB_DATABASE_SQL_VALUE_TYPE_DOUBLE))? tb_true : tb_false;
}
#endif

/// the value is number?
static __tb_inline_force__ tb_bool_t tb_database_sql_value_is_number(tb_database_sql_value_t const* value)
{
    return (value && value->type >= TB_DATABASE_SQL_VALUE_TYPE_INT8 && value->type < TB_DATABASE_SQL_VALUE_TYPE_BLOB8)? tb_true : tb_false;
}

/// the value type
static __tb_inline_force__ tb_size_t tb_database_sql_value_type(tb_database_sql_value_t const* value)
{
    // check
    tb_assert_and_check_return_val(value, TB_DATABASE_SQL_VALUE_TYPE_NULL);

    // the type
    return value->type;
}

/// the value name
static __tb_inline_force__ tb_char_t const* tb_database_sql_value_name(tb_database_sql_value_t const* value)
{
    // check
    tb_assert_and_check_return_val(value, tb_null);

    // the name
    return value->name;
}

/// the value text data
static __tb_inline_force__ tb_char_t const* tb_database_sql_value_text(tb_database_sql_value_t const* value)
{
    // check
    tb_assert_and_check_return_val(value, tb_null);

    // is text?
    if (tb_database_sql_value_is_text(value))
        return value->u.text.data;
    // is blob?
    else if (tb_database_sql_value_is_blob(value))
        return (tb_char_t const*)value->u.blob.data;
    // is null?
    else if (tb_database_sql_value_is_null(value))
        return tb_null;

    // trace
    tb_trace_e("not text value type: %lu", value->type);
    return tb_null;
}

/// the value blob data
static __tb_inline_force__ tb_byte_t const* tb_database_sql_value_blob(tb_database_sql_value_t const* value)
{
    // check
    tb_assert_and_check_return_val(value, tb_null);

    // is blob?
    if (tb_database_sql_value_is_blob(value))
        return value->u.blob.data;
    // is text?
    else if (tb_database_sql_value_is_text(value))
        return (tb_byte_t const*)value->u.text.data;
    // is null?
    else if (tb_database_sql_value_is_null(value))
        return tb_null;

    // trace
    tb_trace_e("not blob value type: %lu", value->type);
    return tb_null;
}

/// the value blob stream
static __tb_inline_force__ tb_stream_ref_t tb_database_sql_value_blob_stream(tb_database_sql_value_t const* value)
{
    // the blob stream
    return tb_database_sql_value_is_blob(value)? value->u.blob.stream : tb_null;
}

/// set the value name
static __tb_inline_force__ tb_void_t tb_database_sql_value_name_set(tb_database_sql_value_t* value, tb_char_t const* name)
{
    // check
    tb_assert_and_check_return(value);

    // set the name
    value->name = name;
}

/* //////////////////////////////////////////////////////////////////////////////////////
 * extern
 */
__tb_extern_c_leave__


#endif
