#include "Asn1cEncDec.hh"
#include "loggers.hh"

//// basic types
//void        titan2asn1c(const INTEGER& t, long& a)
//{
//	if(t.is_native()){
//		a = (int)t;
//	}else{
//		long long int n = t.get_long_long_val();
//		if(n >= LONG_MIN && n <= LONG_MAX){
//			a = (long)n;
//		}else{
//			// TODO: what to do here?
//		}
//	}
//}
//
//void        titan2asn1c(const INTEGER& t, unsigned long& a)
//{
//	if(t.is_native()){
//		int n = (int)t;
//		if(n >= 0) {
//			a = (unsigned)n;
//		}else{
//			// TODO: what to do here?
//		}
//	}else{
//		long long int n = t.get_long_long_val();
//		if(n >= 0 && n <= (long long int)ULONG_MAX){
//			a = (unsigned long)n;
//		}else{
//			// TODO: what to do here?
//		}
//	}
//}
//
//void        titan2asn1c(const INTEGER& t, INTEGER_t& a) {
//	if(t.is_native()){
//		asn_long2INTEGER(&a, (int)t);
//	}else{
//		long long int n = t.get_long_long_val();
//		if(n >= LONG_MIN && n <= LONG_MAX){
//			asn_long2INTEGER(&a, (long)n);
//		}else if(n <= (long long int)ULONG_MAX){
//			asn_ulong2INTEGER(&a, (unsigned long)n);
//		}else{
//			// TODO: what to do here?
//		}
//	}
//}
//
//INTEGER     asn1c2titan(const INTEGER_t& a) {
//	long n;
//	unsigned long un;
//	INTEGER i;
//
//	if( 0 == asn_INTEGER2long(&a, &n)) {
//		i.set_long_long_val((long long int)n);
//	}else if( 0 == asn_INTEGER2ulong(&a, &un)) {
//		i.set_long_long_val((long long int)un);
//	}else{
//		//TODO: What to do?
//	}
//	return i;
//}
//
//INTEGER     asn1c2titan(long n)
//{
//	INTEGER i;
//	i.set_long_long_val(n);
//	return i;
//}
//
//INTEGER     asn1c2titan(unsigned long n)
//{
//	INTEGER i;
//	i.set_long_long_val(n);
//	return i;
//}
//
//void        titan2asn1c(const BOOLEAN& t, BOOLEAN_t& a) {
//	a = ((boolean)t) ? 0xFF : 0x00;
//}
//
//BOOLEAN     asn1c2titan(const BOOLEAN_t& a) {
//	return BOOLEAN(!!a);
//}
//
//void        titan2asn1c(const OCTETSTRING& t, OCTET_STRING_t& a) {
//	OCTET_STRING_fromBuf(&a, (const char*)(const unsigned char*)t, t.lengthof());
//}
//
//OCTETSTRING asn1c2titan(const OCTET_STRING_t& a) {
//	return OCTETSTRING(a.size, a.buf);
//}
//
//void        titan2asn1c(const BITSTRING& t, BIT_STRING_t& a) {
//	int buf_size = (t.lengthof()+7)/8;
//	OCTET_STRING_fromBuf((OCTET_STRING_t*)&a, (const char*)(const unsigned char*)t, buf_size);
//	a.bits_unused = (buf_size*8) - t.lengthof();
//}
//BITSTRING   asn1c2titan(const BIT_STRING_t& a) {
//	return BITSTRING(a.size*8 - a.bits_unused, a.buf);
//}


extern "C" int asn1c_collect_encoded_data(const void *buffer, size_t size, void *application_specific_key)
{
	TTCN_Buffer * tb = (TTCN_Buffer *)application_specific_key;
  tb->put_s(size, (unsigned char *)buffer);
  loggers::get_instance().log_to_hexa("asn1c_collect_encoded_data: Encoding=", *tb);
	return 0;
}

// PER Encoding
#include <ber_decoder.h>
#include <der_encoder.h>
#include <per_encoder.h>
#include <per_decoder.h>

int asn1c_per2ber(asn_TYPE_descriptor_t &td, const TTCN_Buffer & per, TTCN_Buffer & ber, void** ctx )
{
	//void** obj = ctx;
	int rc = -1;
	asn_dec_rval_t rc_d;

	rc_d = uper_decode_complete(NULL, 
                              &td, ctx, 
                              per.get_read_data(), per.get_read_len());

	if(rc_d.code == RC_OK){
		asn_enc_rval_t rc_e;
		ber.clear();
		rc_e = der_encode(&td,
                      (const asn_per_constraints_t*)ctx,
                      asn1c_collect_encoded_data,
                      &ber);
		rc = rc_e.encoded;
	}
	/*if(obj) {
		ASN_STRUCT_FREE(td, obj);
    }*/
	return rc;
}

int asn1c_ber2per(asn_TYPE_descriptor_t &td, const TTCN_Buffer & ber, TTCN_Buffer & per, void** ctx )
{
	//void** obj = ctx;
	int rc = -1;
	asn_dec_rval_t rc_d;
	rc_d = ber_decode( NULL, &td,
                     ctx,
                     ber.get_data(), ber.get_len());
	if(rc_d.code == RC_OK){
    loggers::get_instance().log("asn1c_ber2per: BER decoding succeed");
		asn_enc_rval_t rc_e;
		//per.clear();
		rc_e = uper_encode(&td,
                       NULL,
                       ctx, 
                       asn1c_collect_encoded_data,
                       &per);
		rc = rc_e.encoded;
    if(rc < 0) {
      loggers::get_instance().warning("asn1c_ber2per: PER encoding failed");
    }
	} else {
    loggers::get_instance().warning("asn1c_ber2per: BER decoding failed");
    //    td.free_struct(&td, *ctx, 0);
  }
	/*if(obj) {
		ASN_STRUCT_FREE(td, obj);
    }*/
	return rc;
}

// OER Encoding
//#include <xer_decoder.h>
//#include <xer_encoder.h>
//#include <oer_decoder.h>
//#include <oer_encoder.h>
//
//int asn1c_oer2xer(asn_TYPE_descriptor_t &td, const TTCN_Buffer & oer, TTCN_Buffer & xer, void** ctx )
//{
//	//void** obj = ctx;
//	int rc = -1;
//	asn_dec_rval_t rc_d;
//
//	rc_d = oer_decode(NULL,
//                    &td, ctx,
//                    oer.get_read_data(), oer.get_read_len());
//
//	if(rc_d.code == RC_OK){
//		asn_enc_rval_t rc_e;
//		xer.clear();
//		rc_e = xer_encode(&td,
//                      (const asn_oer_constraints_t*)ctx,
//                      XER_F_BASIC,
//                      asn1c_collect_encoded_data,
//                      &xer);
//		rc = rc_e.encoded;
//	}
//	/*if(obj) {
//		ASN_STRUCT_FREE(td, obj);
//    }*/
//	return rc;
//}
//
//
//int asn1c_xer2oer(asn_TYPE_descriptor_t &td, const TTCN_Buffer & xer, TTCN_Buffer & oer, void** ctx )
//{
//	//void** obj = ctx;
//	int rc = -1;
//	asn_dec_rval_t rc_d;
//	rc_d = xer_decode( NULL, &td,
//                     ctx,
//                     xer.get_data(), xer.get_len());
//	if(rc_d.code == RC_OK){
//    loggers::get_instance().log("asn1c_ber2per: XER decoding succeed");
//		asn_enc_rval_t rc_e;
//		//per.clear();
//		rc_e = oer_encode(&td,
//                       ctx,
//                       asn1c_collect_encoded_data,
//                       &oer);
//		rc = rc_e.encoded;
//    if(rc < 0) {
//      loggers::get_instance().warning("asn1c_ber2per: OER encoding failed");
//    }
//	} else {
//    loggers::get_instance().warning("asn1c_ber2per: XER decoding failed");
//    //    td.free_struct(&td, *ctx, 0);
//  }
//	/*if(obj) {
//		ASN_STRUCT_FREE(td, obj);
//    }*/
//	return rc;
//}

