/****************************************************************************
 * KONOHA COPYRIGHT, LICENSE NOTICE, AND DISCRIMER  
 * 
 * Copyright (c) 2005-2008, Kimio Kuramitsu <kimio at ynu.ac.jp>
 *           (c) 2008-      Konoha Software Foundation  
 * All rights reserved.
 * 
 * You may choose one of the following two licenses when you use konoha. 
 * See www.konohaware.org/license.html for further information.
 * 
 * (1) GNU General Public License 2.0      (with    KONOHA_UNDER_GPL2)
 * (2) Konoha Software Foundation License 1.0
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *  
 ****************************************************************************/

/* ************************************************************************ */

#include"commons.h"

/* ************************************************************************ */

#ifdef __cplusplus 
extern "C" {
#endif

/* ======================================================================== */
/* [define] */

//typedef struct brie_DataTuple {
//	brie_tuplefunc_l func;
//	size_t size;
//	brie_tuplecolumn_t *column;
//	knh_Bytes       *databuf;
//	brie_source_t  *resultptr;
//} brie_DataTuple;

void dbw_DataTuple_initSource(DataTuple *b, dbw_result_t *resultptr, f_dbw_next fn, f_dbw_free ff);

/* ======================================================================== */
/* [structs] */

void dbw_DataTuple_struct_init(Ctx *ctx, Struct *s1, int init, Object *cs)
{
	DataTuple *b =  (DataTuple*)s1;
	b->size = init;
	b->column = knh_malloc(ctx, sizeof(dbw_tuplecolumn_t) * b->size);
	int i = 0;
	for(i = 0; i < b->size; i++) {
		b->column[i].type = CLASS_Object;
		KNH_INITv(b->column[i].name, knh_String_EMPTY());
		b->column[i].start = 0;
		b->column[i].len = 0;
	}
	KNH_INITv(b->databuf, new_Bytes(ctx, 256));
	dbw_DataTuple_initSource(b, NULL, NULL, NULL);
}

/* ------------------------------------------------------------------------ */

#define _dbw_DataTuple_struct_copy NULL

/* ------------------------------------------------------------------------ */

#define _dbw_DataTuple_struct_compare NULL

/* ------------------------------------------------------------------------ */

void dbw_DataTuple_struct_traverse(Ctx *ctx, Struct *s, f_gc gc)
{
	DataTuple *b = (DataTuple*)s;
	gc(ctx, b->databuf);
	int i = 0;
	for(i = 0; i < b->size; i++) {
		gc(ctx, b->column[i].name);
	}
	if(IS_SWEEP(gc)) {
		knh_free(b->column, sizeof(dbw_tuplecolumn_t) * b->size);
		b->column = NULL;
		b->func.free(b->resultptr);
		b->resultptr = NULL;			
	}
}

/* ======================================================================== */
/* [constructors] */


DataTuple* new_dbw_DataTuple(Ctx *ctx, size_t size)
{
#ifdef CLASS_dbw_DataTuple
	DataTuple *b = (DataTuple*)dbw_Object_malloc0(ctx, OF_dbw_DataTuple, CLASS_dbw_DataTuple, sizeof(dbw_DataTuple));
	dbw_DataTuple_struct_init(ctx, (Struct*)b, size, NULL);
	return b;
#else
	return Null;
#endif
}

/* ======================================================================== */
/* [result] */

knh_bool_t dbw_DataTuple_fnext__default(Ctx *ctx, dbw_result_t *resultptr, DataTuple *b)
{
	return 0;
}

/* ------------------------------------------------------------------------ */

void dbw_DataTuple_ffree__default(dbw_result_t *resultptr)
{

}

/* ------------------------------------------------------------------------ */

void dbw_DataTuple_initSource(DataTuple *b, dbw_result_t *resultptr, f_dbw_next fn, f_dbw_free ff)
{
	b->resultptr = resultptr;
	b->func.next = (fn == NULL) ? dbw_DataTuple_fnext__default : fn;
	b->func.free = (ff == NULL) ? dbw_DataTuple_ffree__default : ff;
}

/* ======================================================================== */
/* [next] */

DataTuple *dbw_DataTuple_next(Ctx *ctx, DataTuple *b)
{
	if(b->func.next(ctx, b->resultptr, b)) {
		return b;
	}
	return Null;
}

/* ======================================================================== */
/* [meta] */

void dbw_DataTuple_initMetaInfo(Ctx *ctx, DataTuple *b, size_t n, knh_type_t type, String *name)
{
	DEBUG_ASSERT(n < b->size);
	b->column[n].type = type;
	KNH_SETv(ctx, b->column[n].name, name);
}

/* ------------------------------------------------------------------------ */

knh_index_t dbw_DataTuple_index(Ctx *ctx, DataTuple *b, knh_bytes_t name)
{
	knh_index_t i = 0;
	for(i = 0; i < b->size; i++) {
		if(knh_String_equals(b->column[i].name, name)) return i;
	}
	return -1;
}

/* ------------------------------------------------------------------------ */

String *dbw_DataTuple_getName(Ctx *ctx, DataTuple *b, size_t n)
{
	DEBUG_ASSERT(n < b->size);
	return b->column[n].name;
}

/* ------------------------------------------------------------------------ */

knh_type_t dbw_DataTuple_get_type(Ctx *ctx, DataTuple *b, size_t n)
{
	DEBUG_ASSERT(n < b->size);
	return b->column[n].type;
}

/* ======================================================================== */
/* [set] */

void dbw_DataTuple_initData(Ctx *ctx, DataTuple *b)
{
	int i = 0;
	for(i = 0; i < b->size; i++) {
		b->column[i].ctype = 0;
		b->column[i].start = 0;
		b->column[i].len = 0;
	}
	knh_Bytes_clear(b->databuf);
}

/* ------------------------------------------------------------------------ */

void dbw_DataTuple_set__int(Ctx *ctx, DataTuple *b, size_t n, knh_int_t value)
{
	DEBUG_ASSERT(n < b->size);
	knh_bytes_t t = {(knh_uchar_t*)(&value), sizeof(knh_int_t)};
	b->column[n].ctype = DBW_DATATUPLE_CTYPE__int;
	b->column[n].start = knh_Bytes_size(b->databuf);
	b->column[n].len = sizeof(knh_int_t);
	knh_Bytes_write(ctx, b->databuf, t);
}

/* ------------------------------------------------------------------------ */

void dbw_DataTuple_set__float(Ctx *ctx, DataTuple *b, size_t n, knh_float_t value)
{
	DEBUG_ASSERT(n < b->size);
	knh_bytes_t t = {(knh_uchar_t*)(&value), sizeof(knh_float_t)};
	b->column[n].ctype = DBW_DATATUPLE_CTYPE__float;
	b->column[n].start = knh_Bytes_size(b->databuf);
	b->column[n].len = sizeof(knh_float_t);
	knh_Bytes_write(ctx, b->databuf, t);
	int i, c = t.len % sizeof(void*);
	for(i = 0; i < c; i++) knh_Bytes_putc(ctx, b->databuf, 0);    /* zero */
}

/* ------------------------------------------------------------------------ */

void dbw_DataTuple_set__int64(Ctx *ctx, DataTuple *b, size_t n, knh_int64_t value)
{
	DEBUG_ASSERT(n < b->size);
	knh_bytes_t t = {(knh_uchar_t*)(&value), sizeof(knh_int64_t)};
	b->column[n].ctype = DBW_DATATUPLE_CTYPE__int64;	
	b->column[n].start = knh_Bytes_size(b->databuf);
	b->column[n].len = sizeof(knh_int64_t);
	knh_Bytes_write(ctx, b->databuf, t);
}

/* ------------------------------------------------------------------------ */

void dbw_DataTuple_set__bytes(Ctx *ctx, DataTuple *b, size_t n, knh_bytes_t t)
{
	DEBUG_ASSERT(n < b->size);
	b->column[n].ctype = DBW_DATATUPLE_CTYPE__bytes;
	b->column[n].start = knh_Bytes_size(b->databuf);
	b->column[n].len = t.len;
	knh_Bytes_write(ctx, b->databuf, t);
	int i, c = t.len % sizeof(void*);
	for(i = 0; i < c; i++) knh_Bytes_putc(ctx, b->databuf, 0);    /* zero */
}

/* ------------------------------------------------------------------------ */

void dbw_DataTuple_set__null(Ctx *ctx, DataTuple *b, size_t n)
{
	DEBUG_ASSERT(n < b->size);
	b->column[n].ctype = DBW_DATATUPLE_CTYPE__null;
	b->column[n].start = knh_Bytes_size(b->databuf);
	b->column[n].len = 0;
}

/* ------------------------------------------------------------------------ */

knh_int_t dbw_DataTuple_get__int(Ctx *ctx, DataTuple *b, size_t n)
{
	DEBUG_ASSERT(n < b->size);
	char *p = knh_Bytes_tochar(b->databuf) + b->column[n].start;
	switch(b->column[n].ctype) {
	case DBW_DATATUPLE_CTYPE__null :
		return 0;
	case DBW_DATATUPLE_CTYPE__int :
		return (knh_int_t)(*((knh_int_t*)p));
	case DBW_DATATUPLE_CTYPE__float :
		return (knh_int_t)(*((knh_float_t*)p));
	case DBW_DATATUPLE_CTYPE__int64 :
		return (knh_int_t)(*((knh_int64_t*)p));
	case DBW_DATATUPLE_CTYPE__bytes :
		return knh_bytes_toint(B2(p, b->column[n].len));
	}
	return 0;
}

/* ------------------------------------------------------------------------ */

knh_float_t dbw_DataTuple_get__float(Ctx *ctx, DataTuple *b, size_t n)
{
	DEBUG_ASSERT(n < b->size);
	char *p = knh_Bytes_tochar(b->databuf) + b->column[n].start;
	switch(b->column[n].ctype) {
	case DBW_DATATUPLE_CTYPE__null :
		return 0.0;
	case DBW_DATATUPLE_CTYPE__int :
		return (knh_float_t)(*((knh_int_t*)p));
	case DBW_DATATUPLE_CTYPE__float :
		return (knh_float_t)(*((knh_float_t*)p));
	case DBW_DATATUPLE_CTYPE__int64 :
		return (knh_float_t)(*((knh_int64_t*)p));
	case DBW_DATATUPLE_CTYPE__bytes :
		return knh_bytes_tofloat(B2(p, b->column[n].len));
	}
	return 0.0;
}

/* ------------------------------------------------------------------------ */

knh_int64_t dbw_DataTuple_get__int64(Ctx *ctx, DataTuple *b, size_t n)
{
	char *p = knh_Bytes_tochar(b->databuf) + b->column[n].start;
	switch(b->column[n].ctype) {
	case DBW_DATATUPLE_CTYPE__null :
		return 0L;
	case DBW_DATATUPLE_CTYPE__int :
		return (knh_int64_t)(*((knh_int_t*)p));
	case DBW_DATATUPLE_CTYPE__float :
		return (knh_int64_t)(*((knh_float_t*)p));
	case DBW_DATATUPLE_CTYPE__int64 :
		return (knh_int64_t)(*((knh_int64_t*)p));
	case DBW_DATATUPLE_CTYPE__bytes :
		return knh_bytes_toint64(B2(p, b->column[n].len));
	}
	return 0L;
}

/* ------------------------------------------------------------------------ */

Object *dbw_DataTuple_get(Ctx *ctx, DataTuple *b, size_t n)
{
	Object *v;
	knh_class_t cid = TYPE_UNMASK(b->column[n].type);
	knh_class_t bcid = knh_tclass_bcid(cid);
	switch(bcid) {
	case CLASS_Int :
		v = new_Int__checked(ctx, cid, dbw_DataTuple_get__int(ctx, b, n));
		if(IS_NULL(v) && TYPE_ISNOTNULL(b->column[n].type)) {
			KNH_SAFEFREE(ctx, v);
			TODO();
			return knh_tclass_value(ctx, cid, NULL);
		}
		return v;
	case CLASS_Float :
		v = new_Float__checked(ctx, cid, dbw_DataTuple_get__float(ctx, b, n));
		if(IS_NULL(v) && TYPE_ISNOTNULL(b->column[n].type)) {
			KNH_SAFEFREE(ctx, v);
			TODO();
			return knh_tclass_value(ctx, cid, NULL);
		}
		return v;
	case CLASS_Int64 :
		v = new_Int64__checked(ctx, cid, dbw_DataTuple_get__int64(ctx, b, n));
		if(IS_NULL(v) && TYPE_ISNOTNULL(b->column[n].type)) {
			KNH_SAFEFREE(ctx, v);
			TODO();
			return knh_tclass_value(ctx, cid, NULL);
		}
		return v;
#ifdef CLASS_Decimal
	case CLASS_Decimal :
		TODO();
		return Null;
#endif
	case CLASS_String :
		v = new_String__checked(ctx, cid, B2(knh_Bytes_tochar(b->databuf) + b->column[n].start, b->column[n].len));
		if(IS_NULL(v) && TYPE_ISNOTNULL(b->column[n].type)) {
			KNH_SAFEFREE(ctx, v);
			TODO();
			return knh_tclass_value(ctx, cid, NULL);
		}
		return v;
	}
	DEBUG("unsupported type cid=%s, bcid=%s", CLASSN(cid), CLASSN(bcid));
	return Null;
}

/* ------------------------------------------------------------------------ */

#ifdef __cplusplus
}
#endif
