/* This is part of the Aw:: Perl module.  A Perl interface to the ActiveWorks(tm) 
   libraries.  Copyright (C) 1999-2000 Daniel Yacob.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif


#include "awadapter.h"
#include "aweb.h"

#include "awxs.h"
#include "awxs.def"

#include "exttypes.h"

#include "HashToEvent.h"

BrokerEvent hashToEvent ( BrokerEvent event, char * field_name, HV* hv );

char * stradd ( char* stringA, char* stringB );


char *
stradd ( char* stringA, char* stringB )
{
char * returnString = NULL;

	if ( stringB == NULL )
		return ( NULL );
	
	if ( stringA == NULL )
		returnString = strdup (stringB);
	else
	  {
		returnString = (char *)safemalloc ( sizeof(char)*( strlen(stringA) + strlen(stringB) + 1) );

		sprintf ( returnString, "%s%s", stringA, stringB );	
	  }

	return ( returnString );
}



BrokerError
awxsSetField ( BrokerEvent event, char * field_name, short field_type, SV* sv, BrokerEvent rootEvent, char * full_field_name )
{
BrokerError err = NULL;


#if	AWXS_DEBUG
	printf ("    Hello from awxsSetField[%i]\n", field_type);
	if ( full_field_name )
		printf ( "     Struct Member: %s/%s\n", field_name, full_field_name );
	else
		printf ( "     Struct Member: %s/root\n", field_name );
#endif /* DEBUG */

	if ( sv == NULL )
		awSetField ( event, field_name, field_type, NULL );
	else switch ( field_type )
	  {
		case FIELD_TYPE_BOOLEAN:
			{
			BrokerBoolean value = (BrokerBoolean)SvUV( sv );
			err = awSetBooleanField ( event, field_name, value );
			}
			break;

		case FIELD_TYPE_BYTE:
			{
			BrokerByte value = (BrokerByte)SvUV( sv );
			err = awSetByteField ( event, field_name, value );
			}
			break;

		case FIELD_TYPE_CHAR:
			{
			char value = (unsigned char)*SvPV( sv, PL_na );
			err = awSetCharField ( event, field_name, value );
			}
			break;

		case FIELD_TYPE_DATE:
			{
			BrokerDate * date = (BrokerDate *)SvIV((SV*)SvRV( sv ));
			err = awSetDateField ( event, field_name, *date );
			}
			break;

		case FIELD_TYPE_DOUBLE:
			{
			double value = (double)SvNV( sv );
			err = awSetDoubleField ( event, field_name, value );
			}
			break;

		case FIELD_TYPE_FLOAT:
			{
			float value = (float)SvNV( sv );
			err = awSetFloatField ( event, field_name, value );
			}
			break;

		case FIELD_TYPE_INT:
			{
			int value = (int)SvIV( sv );
			err = awSetIntegerField ( event, field_name, value );
			}
			break;

		case FIELD_TYPE_LONG:
			{
			BrokerLong value;
			value = awBrokerLongFromString ( longlong_to_string ( SvLLV( sv ) ) );
			err = awSetLongField ( event, field_name, value );
			}
			break;

		case FIELD_TYPE_SHORT:
			{
			short value = (short)SvIV( sv );
			err = awSetShortField ( event, field_name, value );
			}
			break;

		case FIELD_TYPE_STRING:
			{
			char * value = (unsigned char *)SvPV( sv, PL_na );
			err = awSetStringField ( event, field_name, value );
			}
			break;

		case FIELD_TYPE_SEQUENCE:
			err = awxsSetSequenceField ( event, field_name, field_type, 0, 0, (AV*) SvRV(sv), rootEvent, full_field_name );
			break;

		case FIELD_TYPE_STRUCT:
			{
			BrokerEvent hEvent;
			if ( !rootEvent ) {
				rootEvent       = event;
				full_field_name = field_name;
			}

			hEvent
			= ( sv_isobject ( sv ) && sv_derived_from ( sv, "Aw::Event" ) )
			  ? ((xsBrokerEvent *)SvIV((SV*)SvRV( sv )))->event
			  : setStructFieldFromEvent ( event, full_field_name, (HV*)SvRV(sv), rootEvent )
			;
			err = awSetStructFieldFromEvent ( event, field_name, hEvent );
			}
			break;

		case FIELD_TYPE_UNICODE_CHAR:
			{
			char * utf8ch = (unsigned char *)SvPV( sv, PL_na );
			charUC *ucCh;
			ucCh = awUTF8toUC ( utf8ch );
			err  = awSetUCCharField ( event, field_name, ucCh[0] );
			}
			break;

		case FIELD_TYPE_UNICODE_STRING:
			{
			char * value = (unsigned char *)SvPV( sv, PL_na );
			err = awSetUCStringFieldAsUTF8 ( event, field_name, value );
			}
			break;

		default:
		case FIELD_TYPE_UNKNOWN:
#if 0
			errMsg = setErrMsg ( 1, "Unknown Field Type" );
#ifdef AWXS_WARNS
			if ( myWarn )
				warn ( errMsg );
#endif /* AWXS_WARNS */
#endif
			break;
		  }

#if    AWXS_DEBUG
	printf ("        GoodBye from awxsSetField\n" );
#endif /* DEBUG */

	return ( err );

}



BrokerError
awxsSetSequenceField ( BrokerEvent event, char * field_name, short field_type, int src_offset, int dest_offset, AV* av, BrokerEvent rootEvent, char * full_field_name )
{
int i, n;
SV ** sv;
void * value;
BrokerError err = NULL;

int * iValue;
short * sValue;
float * fValue;
double * dValue;
unsigned char ** stValue;
charUC * ucValue;
charUC ** ucstValue;
BrokerByte * byValue;
BrokerLong * blValue;
BrokerDate * bdValue;
unsigned char * cValue;
BrokerBoolean * boValue;
BrokerEvent * eValue = NULL;
char * orig_field_name = NULL;
short seq_field_type;
int * ix;

#if    AWXS_DEBUG
	printf ("    Hello from awxsSetSequenceField[%i]\n", field_type);
#endif /* DEBUG */


	orig_field_name = strdup ( field_name );
	if ( field_type == FIELD_TYPE_SEQUENCE ) {
		field_name = stradd ( field_name, "[]" );
		if ( rootEvent )
		  {
			/*  Any time we "get" info it has to be from the original event
			 *  using the fully qualified structure path
                         */
			full_field_name = stradd ( full_field_name, "[]" );
#if    AWXS_DEBUG
			printf ( "  Has Root:  %s\n", full_field_name );
#endif /* DEBUG */
			awGetEventFieldType ( rootEvent, full_field_name, &seq_field_type);
		  }
		else
			awGetEventFieldType ( event, field_name, &seq_field_type);
		field_type = seq_field_type;
#if    AWXS_DEBUG
		printf ( "  %s => %i\n", field_name, field_type );
#endif /* DEBUG */
	}


	if ( av == NULL ) {
		err = awSetSequenceField ( event, orig_field_name, field_type, src_offset, dest_offset, 0, NULL );
		return ( err );
	}

	
	n  = av_len ( av ) + 1;

#if    AWXS_DEBUG
	printf ( "  %i elements of type %i\n", n, field_type );
#endif /* DEBUG */

	switch (field_type)
	  {
		case FIELD_TYPE_BOOLEAN:
			value = boValue = (BrokerBoolean *)safemalloc ( n * sizeof( BrokerBoolean ) );
			break;

		case FIELD_TYPE_BYTE:
	   		value = byValue = (BrokerByte *)safemalloc ( n * sizeof( BrokerByte ) );
			break;

		case FIELD_TYPE_CHAR:
			value = cValue = (unsigned char *)safemalloc ( n * sizeof( char ) );
			break;

		case FIELD_TYPE_INT:
			// printf ( "Mallocing %d Elements.\n", n );
			value = iValue = (int *)safemalloc ( (n+1) * sizeof( int ) );
			break;

		case FIELD_TYPE_LONG:
			value = blValue = (BrokerLong *)safemalloc ( n * sizeof( BrokerLong ) );
			break;

		case FIELD_TYPE_SHORT:
			value = sValue = (short *)safemalloc ( n * sizeof( short ) );
			break;

		case FIELD_TYPE_DATE:
	   		value = bdValue = (BrokerDate *)safemalloc ( n * sizeof( BrokerDate ) );
			break;

		case FIELD_TYPE_DOUBLE:
			value = dValue = (double *)safemalloc ( n * sizeof( double ) );
			break;

		case FIELD_TYPE_FLOAT:
			value = fValue = (float *)safemalloc ( n * sizeof( float ) );
			break;

		case FIELD_TYPE_STRING:
			value = stValue = (unsigned char **)safemalloc ( n * sizeof( char * ) );
			break;

		case FIELD_TYPE_STRUCT:
			eValue = (BrokerEvent *)safemalloc ( n * sizeof( BrokerEvent ) );
			break;

		case FIELD_TYPE_UNICODE_CHAR:
			value = ucValue = (charUC *)safemalloc ( n * sizeof( charUC ) );
			break;

		case FIELD_TYPE_UNICODE_STRING:
			value = ucstValue = (charUC **)safemalloc ( n * sizeof( charUC *) );
		default:
			break;
	  }



	for ( i=0; i<n; i++ ) {
		sv = av_fetch ( av, i, 0 );
		switch (field_type)
		  {
			case FIELD_TYPE_BOOLEAN:
				boValue[i] = (BrokerBoolean)SvUV(*sv);
				break;

			case FIELD_TYPE_BYTE:
		   		byValue[i] = (BrokerByte)SvUV(*sv);
				break;

			case FIELD_TYPE_CHAR:
				cValue[i] =* (unsigned char *)SvPV(*sv,PL_na);
				break;

			case FIELD_TYPE_INT:
				iValue[i] = (int)SvIV(*sv);
				break;

			case FIELD_TYPE_LONG:
				blValue[i] = awBrokerLongFromString ( longlong_to_string ( SvLLV(*sv) ) );
				break;

			case FIELD_TYPE_SHORT:
				sValue[i] = (short)SvIV(*sv);
				break;

			case FIELD_TYPE_DATE:
		   		bdValue[i] =* (BrokerDate *)SvIV((SV*)SvRV( *sv ));
				break;

			case FIELD_TYPE_DOUBLE:
				dValue[i] = (double)SvNV(*sv);
				break;

			case FIELD_TYPE_FLOAT:
				fValue[i] = (float)SvNV(*sv);
				break;

			case FIELD_TYPE_STRING:
				stValue[i] = (unsigned char *)SvPV(*sv,PL_na);
				break;

			case FIELD_TYPE_STRUCT:
				if ( SvROK( *sv ) && (SvTYPE(SvRV( *sv )) != SVt_PVHV) ) {
					printf ( "SV is NOT an HV is a %i!\n", SvTYPE( SvRV(*sv) ) );
				 
					exit (1);
				} 
				if ( !rootEvent ) {
					rootEvent       = event;
					full_field_name = field_name;
				}
				eValue[i]
				= ( sv_isobject ( *sv ) && sv_derived_from ( *sv, "Aw::Event" ) )
			  	  ? ((xsBrokerEvent *)SvIV((SV*)SvRV( *sv )))->event
			  	  : setStructFieldFromEvent ( event, full_field_name, (HV*)SvRV(*sv), rootEvent )
				;
				break;

			case FIELD_TYPE_UNICODE_CHAR:
				{
				char * utf8Ch;
				charUC * ucCh;
				utf8Ch = (unsigned char *)SvPV(*sv,PL_na);
				ucCh = awUTF8toUC( utf8Ch );
				ucValue[i] = ucCh[0];
				Safefree ( ucCh );
				}
				break;

			case FIELD_TYPE_UNICODE_STRING:
				ucstValue[i] = awUTF8toUC( (unsigned char *)SvPV(*sv,PL_na) );
				break;

			case FIELD_TYPE_SEQUENCE:
				return ( awxsSetSequenceField ( event, field_name, field_type, src_offset, dest_offset, av, rootEvent, full_field_name ) );
				break;

			default:
				break;
		  }
	}




	if ( field_type == FIELD_TYPE_STRUCT )
	  {
		err = awSetStructSeqFieldFromEvents ( event, orig_field_name, src_offset, dest_offset, n, eValue );

		for ( i = 0; i<n; i++ )
		 	awDeleteEvent ( eValue[i] );

		Safefree ( eValue );
	  }
	else
	  {
		err = awSetSequenceField ( event, orig_field_name, field_type, src_offset, dest_offset, n, value );
		Safefree ( value );
	  }


	return ( err );


}



BrokerEvent
hashToEvent ( BrokerEvent Event, char * field_name, HV* hv )
{
BrokerEvent * myStruct;
BrokerError err = NULL;
int i, n;
char *key, *value;
HE *entry;


// printf ("      Hello from hashToEvent\n" );


	myStruct = (BrokerEvent *) safemalloc ( sizeof(BrokerEvent) );
	err = awNewBrokerEvent ( NULL, "Dumb::MiniMeEvent", myStruct );


	hv_iterinit ( hv );
	n = HvKEYS( hv );
	
// printf ("        n = %i\n", n );
					
	for ( i=0; i<n; i++ ) { 
		entry = hv_iternext ( hv );
		key   = HeKEY(entry);
		value = SvPV (HeVAL ( entry ), PL_na);
		// printf ( "      %s => %s\n", key, value );
		err   = awSetStringField ( *myStruct, key, value ); 
	}

// printf ("        GoodBye from hashToEvent\n" );
	return ( *myStruct );

}



BrokerEvent
setStructFieldFromEvent ( BrokerEvent event, char * full_field_name, HV * hv, BrokerEvent rootEvent )
{
int i, n;
HE *entry;
SV* value;
char * key;
short field_type;
BrokerError err = NULL;
BrokerEvent * childEvent;
char * member_name;



	if ( rootEvent == NULL )
		rootEvent = event;

#if    AWXS_DEBUG
	printf ( "        Hello from setStructFieldFromEvent [%s]\n", full_field_name );
#endif /* DEBUG */


	childEvent = (BrokerEvent *) safemalloc ( sizeof(BrokerEvent) );
	err = awNewBrokerEvent ( NULL, "Dumb::MiniMeEvent", childEvent );

	full_field_name = stradd ( full_field_name, "." );


	hv_iterinit ( hv );
	n = HvKEYS( hv );


	for ( i=0; i<n; i++ )
	  {
		entry = hv_iternext ( hv );
		key   = HeKEY ( entry );
		value = HeVAL ( entry );
		
		member_name = stradd ( full_field_name, key );
		awGetEventFieldType ( rootEvent, member_name, &field_type );

		if ( field_type == FIELD_TYPE_SEQUENCE )
			awxsSetSequenceField ( *childEvent, key, field_type, 0, 0, (AV*)SvRV(value), rootEvent, member_name );
		else
			{
			if ( value == NULL )
				warn ( "      >>Field Value is NULL %s\n", key );
			else
				awxsSetField ( *childEvent, key, field_type, value, rootEvent, member_name );
			}

		Safefree ( member_name );
	  }


#if    AWXS_DEBUG
	printf ( "        GoodBye from setStructFieldFromEvent\n" );
#endif /* DEBUG */

	return ( *childEvent );
}



void
hashWalk ( HV * hv )
{
int i, n;
char *key, *value;
HE *entry;
SV *sv;

	printf ( "In hashWalk\n" );
	hv_iterinit ( hv );
	n = HvKEYS( hv );
	printf ( "n = %i\n", n );

	for ( i=0; i<n; i++ ) { 
		entry = hv_iternext ( hv );
		key   = HeKEY(entry);
		printf ( "  %s => ", key );
		sv = HeVAL ( entry );
		if ( SvROK( sv ) && (SvTYPE(SvRV( sv )) == SVt_PVHV) )
		  hashWalk ( (HV*)SvRV(sv) );	
		else
		  value = SvPV ( sv, PL_na);
		printf ( "  %s\n", value );
	}


}



BrokerError
awxsSetEventFromHash ( BrokerEvent event, HV * hv )
{
int i, n;
HE *entry;
SV* value;
char * key;
short field_type;
BrokerError err = NULL;



#if    AWXS_DEBUG
	printf ( "        Hello from setEventFromHash \n" );
#endif /* DEBUG */


	hv_iterinit ( hv );
	n = HvKEYS ( hv );

#if    AWXS_DEBUG
	printf ( "          %i Hash Elements\n", n );
#endif /* DEBUG */


	for ( i=0; i<n; i++ )
	  {
		entry = hv_iternext ( hv );
		key   = HeKEY ( entry );
		value = HeVAL ( entry );
		
		awGetEventFieldType ( event, key, &field_type );

		if ( field_type == FIELD_TYPE_SEQUENCE )
			err = awxsSetSequenceField ( event, key, field_type, 0, 0, (AV*)SvRV(value), NULL, NULL );
		else
			{
			if ( value == NULL )
				warn ( "      >>Field Value is NULL %s\n", key );
			else
				err = awxsSetField ( event, key, field_type, value, NULL, NULL );
			}

	  }


#if    AWXS_DEBUG
	printf ( "        GoodBye from setEventFromHash\n" );
#endif /* DEBUG */

	return ( err );
}



BrokerError
awxsSetEventFromTypedHash ( BrokerEvent event, HV * data, HV * type )
{
int i, n;
HE* entry;
SV* value;
SV** ssv;
char * key;
short field_type;
BrokerError err = NULL;



#if    AWXS_DEBUG
	printf ( "        Hello from setEventFromTypedHash \n" );
#endif /* DEBUG */


	n = hv_iterinit ( data );


	for ( i=0; i<n; i++ )
	  {
		entry = hv_iternext ( data );
		key   = HeKEY ( entry );
		value = HeVAL ( entry );
		ssv = hv_fetch ( type, key, strlen(key), 0 );
		field_type = (short)SvIV( *ssv );
		
		if ( field_type == FIELD_TYPE_SEQUENCE )
			err = awxsSetSequenceField ( event, key, field_type, 0, 0, (AV*)SvRV(value), NULL, NULL );
		else
			{
			if ( value == NULL )
				warn ( "      >>Field Value is NULL %s\n", key );
			else
				err = awxsSetField ( event, key, field_type, value, NULL, NULL );
			}

	  }


#if    AWXS_DEBUG
	printf ( "        GoodBye from setEventFromTypedHash\n" );
#endif /* DEBUG */

	return ( err );
}
