/*
 * Copyright (c) 2004, 2005, 2006 TADA AB - Taby Sweden
 * Distributed under the terms shown in the file COPYRIGHT
 * found in the root folder of this project or at
 * http://eng.tada.se/osprojects/COPYRIGHT.html
 *
 * @author Thomas Hallgren
 */
#include "pljava/type/Type_priv.h"
#include "pljava/type/HeapTupleHeader.h"

#include <executor/executor.h>
#include <executor/spi.h>
#include <utils/typcache.h>

#include "pljava/Exception.h"
#include "pljava/Invocation.h"
#include "pljava/HashMap.h"
#include "pljava/type/TupleDesc.h"

static HashMap s_TupleDescMap = 0;

jobject HeapTupleHeader_getStaticTupleDesc(HeapTupleHeader ht)
{
	TupleDesc td = lookup_rowtype_tupdesc(
		HeapTupleHeaderGetTypeId(ht),
		HeapTupleHeaderGetTypMod(ht));

	jobject tupleDesc = HashMap_getByOpaque( s_TupleDescMap, td );
	if(tupleDesc)
	{
		DecrTupleDescRefCount(td);
		return tupleDesc;
	}
	else
	{
		tupleDesc = JNI_newGlobalRef( TupleDesc_create( td ));
		HashMap_putByOpaque( s_TupleDescMap, td, tupleDesc );
		return tupleDesc;
	}
/*	return TupleDesc_create(
 *		lookup_rowtype_tupdesc(
 *			HeapTupleHeaderGetTypeId(ht),
 *			HeapTupleHeaderGetTypMod(ht)));
 */
}


jobject HeapTupleHeader_getTupleDesc(HeapTupleHeader ht)
{
	return TupleDesc_create(
		lookup_rowtype_tupdesc(
			HeapTupleHeaderGetTypeId(ht),
			HeapTupleHeaderGetTypMod(ht)));
}

jobject HeapTupleHeader_getObject(JNIEnv* env, jlong hth, jlong jtd, jint attrNo)
{
	jobject result = 0;
	HeapTupleHeader self = (HeapTupleHeader)Invocation_getWrappedPointer(hth);
	if(self != 0 && jtd != 0)
	{
		Ptr2Long p2l;
		p2l.longVal = jtd;
		BEGIN_NATIVE
		PG_TRY();
		{
			Oid typeId = SPI_gettypeid((TupleDesc)p2l.ptrVal, (int)attrNo);
			if(!OidIsValid(typeId))
			{
				Exception_throw(ERRCODE_INVALID_DESCRIPTOR_INDEX,
					"Invalid attribute number \"%d\"", (int)attrNo);
			}
			else
			{
				Datum binVal;
				bool wasNull = false;
				Type type = Type_fromOid(typeId, Invocation_getTypeMap());
				if(Type_isPrimitive(type))
					/*
					 * This is a primitive type
					 */
					type = Type_getObjectType(type);
	
				binVal = GetAttributeByNum(self, (AttrNumber)attrNo, &wasNull);
				if(!wasNull)
					result = Type_coerceDatum(type, binVal).l;
			}
		}
		PG_CATCH();
		{
			Exception_throw_ERROR("GetAttributeByNum");
		}
		PG_END_TRY();
		END_NATIVE
	}
	return result;
		
}

void HeapTupleHeader_free(JNIEnv* env, jlong hth)
{
	BEGIN_NATIVE_NO_ERRCHECK
	Invocation_freeLocalWrapper(hth);
	END_NATIVE
}

void HeapTupleHeader_initialize(void)
{
	s_TupleDescMap = HashMap_create( 13, TopMemoryContext );
}
