#include <iomanip>
#include <iostream>
#include <ext/hash_map>
#include <cstring>
#include <cstdio>

#include "vars.h"
#include "safestring.h"

//#include "soapBasicHttpBinding_USCOREQuickTellerServiceProxy.h" // get proxy
//#include "BasicHttpBinding_USCOREQuickTellerService.nsmap" // obtain the generated XML namespace mapping table for the InterSwitch service
#include "interswitchBasicHttpBinding_USCOREQuickTellerServiceProxy.h" // get proxy
#include "interswitch.nsmap" // obtain the generated XML namespace mapping table for the InterSwitch service
#include "sha512.h"
#include "XmlParser.h"
#include "interswitch.h"


#define BUFSIZE 1024

// global SSL configuration
char interswitch_ssl_keyfile[256];
char interswitch_ssl_password[20];
char interswitch_ssl_cacert[256];
int  interswitch_ssl_configured = 0;
long interswitch_ssl_version = 0;

using namespace interswitch;
using namespace std;
using namespace __gnu_cxx;

#ifdef TEST
#include <stdio.h>
#include <stdarg.h>
enum { FLOG_NONE,FLOG_FATAL,FLOG_CRITICAL,FLOG_WARN,FLOG_COMMAND,FLOG_MAX };
#define logfmt interswitch_test_log
#define PREFIX "FAKE:"
class InterswitchFakeLog {
  public:
    void SetFileName(const char *str) {
      cout << str << endl;
    }
};
static InterswitchFakeLog *plog = new InterswitchFakeLog();
#else
//#include "general_types.h"
#include "clog.h"
#warning "Including log..."
#endif

void interswitch_test_log( int level, const char * format, ... ) {

  va_list ap;
  va_start( ap, format );

  vfprintf( stdout, format, ap );
  fprintf( stdout, "\n" );

  fflush( stdout );

  va_end( ap );
}

/*****************************************************************************/
/*
long interswitch_digest_to_vector(unsigned char *vector, unsigned char *digest, unsigned int digest_size) {
	unsigned char output[2 * SHA512_DIGEST_SIZE + 1];
	int i;
	output[2 * digest_size] = '\0';

	for (i = 0; i < digest_size ; i++) {
 		sprintf((char *) output + 2*i, "%02x", digest[i]);
	}

	logfmt(FLOG_MAX, "H: %s", output);
	if (strcmp((char *) vector, (char *) output)) {
		logfmt(FLOG_MAX, "Hash failed");
		return -1;
	}
	return 0;
}
*/
/*****************************************************************************/
/*
struct eqstr{
  bool operator()(const char* s1, const char* s2) const {
    return strcmp(s1,s2)==0;
  }
};
*/
/*****************************************************************************/
long interswitch_config_ssl(const char *keyfile, const char *password, const char *cacert, long version) {
	// setup global SSL configuration
	//interswitch_ssl_configured = 0;
	memset(interswitch_ssl_keyfile,0,256);
	snprintf(interswitch_ssl_keyfile,256,"%s",keyfile);
	memset(interswitch_ssl_password,0,20);
	snprintf(interswitch_ssl_password,20,"%s",password);
	memset(interswitch_ssl_cacert,0,256);
	snprintf(interswitch_ssl_cacert,256, "%s",cacert);
	interswitch_ssl_configured = 1;
	interswitch_ssl_version = version;
	return 1L;
}
/*****************************************************************************/
int ParseInterswitchGetBillersResponse(const char *xmlstring,long(*save)(hash_map<const char*, const char*, hash<const char*>, eqstr>)) { //(long, char*, long, char*, char*)) {

	logfmt(FLOG_MAX,"int ParseInterswitchGetBillersResponse(const char *xmlstring,long(*save)(long, char*, long, char*, char*))");

  using namespace SimpleXMLParser;

#ifdef TEST
  cout << "RAW: " << xmlstring << endl;
#endif

  XmlParser parser;
  const Element& root = parser.Parse(xmlstring,strlen(xmlstring));

  if (root.GetName()!="Response") {
    logfmt(FLOG_MAX,"Unknown XML response");
    return -1;
  }
	// Data
	//long id, currency_code;
	//char name[256], quick_teller_site_url_name[256], support_email[256];
	hash_map<const char*, const char*, hash<const char*>, eqstr> saveData;

	int ret = -2; // Empty result
	const Elements* classes = root.GetChildren();
	if(classes != 0) {
		ret = 0; // We will return how manu billers parsed
		for(Elements::const_iterator class_it = classes->begin();class_it != classes->end(); ++class_it) {
			if((*class_it)->GetName()=="ResponseCode") {
				const string value = (*class_it)->GetValue();
				logfmt(FLOG_MAX,"Parsed ResponseCode: %s", value.c_str());
        if (atoi(value.c_str())!=90000) {
					ret = -3; // NOT SUCCESSFUL
					break;
				}
      } else if ((*class_it)->GetName()=="BillerList") {
				// Iterate categories under biller list
				const Elements* categories = (*class_it)->GetChildren();
				if (categories!=0) {
					for(Elements::const_iterator category_it = categories->begin();category_it != categories->end(); ++category_it) {
						if ((*category_it)->GetName()=="Category") {
							// Iterate billers under category
							const Elements* billers = (*category_it)->GetChildren();
							if (billers!=0) {
								for(Elements::const_iterator biller_it = billers->begin();biller_it!= billers->end(); ++biller_it) {
									if((*biller_it)->GetName()=="Biller") {
										// New biller
										//id = 0L;
										//currency_code = 0L;
										//memset(name,0,256);
										//memset(quick_teller_site_url_name,0,256);
										//memset(support_email,0,256);
										// Parse Biller
										const Elements* data = (*biller_it)->GetChildren();
										if (data!=0) {
											for (Elements::const_iterator data_it = data->begin();data_it != data->end(); ++data_it) {
												const string key = (*data_it)->GetName();
												const string val = (*data_it)->GetValue();
												saveData[key.c_str()] = val.c_str();
/*
												if ((*data_it)->GetName()=="Id") {
													const string value = (*data_it)->GetValue();
													id = atol(value.c_str());
												} else if ((*data_it)->GetName()=="Name") {
													const string value = (*data_it)->GetValue();
													snprintf(name,256,"%s",value.c_str());
												} else if ((*data_it)->GetName()=="CurrencyCode") {
													const string value = (*data_it)->GetValue();
													currency_code = atol(value.c_str());
												} else if ((*data_it)->GetName()=="QuickTellerSiteUrlName") {
													const string value = (*data_it)->GetValue();
													snprintf(quick_teller_site_url_name,256,"%s",value.c_str());
												} else if ((*data_it)->GetName()=="SupportEmail") {
													const string value = (*data_it)->GetValue();
													snprintf(support_email,256,"%s",value.c_str());
												}
*/
											}
											// Save data
											hash_map<const char*, const char*, hash<const char*>, eqstr>::iterator pointer;
											for (pointer = saveData.begin();pointer!=saveData.end();++pointer) {
												//logfmt(FLOG_MAX, "'%s' => '%s'", pointer->first, pointer->second);
											}
											if (save!=NULL) {
												save (saveData);
											}
											ret++;
										} else {
											logfmt(FLOG_MAX,"Empty biller node?");
										}
									}
								}
							} else {
								logfmt(FLOG_MAX,"Empty category?");
							}
						}
					}
				} else {
					logfmt(FLOG_MAX,"Empty biller list?");
				}
      } else {
       	logfmt(FLOG_MAX,"Skipped element: %s", (*class_it)->GetName().c_str());
      }
    }
  } else {
		logfmt(FLOG_MAX,"Empty response?");
	}
	return 0;
}
/*****************************************************************************/
int ParseInterswitchGetBillerPaymentItemsResponse(const char *xmlstring,long(*save)(const char*, hash_map<const char*, const char*, hash<const char*>, eqstr>)) { //(long, char*, long, char*, char*)) {

	logfmt(FLOG_MAX,"int ParseInterswitchGetBillerPaymentItemsResponse(const char *xmlstring,long(*save)(long, char*, long, char*, char*))");

	using namespace SimpleXMLParser;

#ifdef TEST
	cout << "RAW: " << xmlstring << endl;
#endif

	XmlParser parser;
	const Element& root = parser.Parse(xmlstring,strlen(xmlstring));

	if (root.GetName()!="Response") {
		logfmt(FLOG_MAX,"Unknown XML response");
		return -1;
	}
	hash_map<const char*, const char*, hash<const char*>, eqstr> saveData;
	int ret = -2; // Empty result
	const Elements* classes = root.GetChildren();
	if(classes != 0) {
		ret = 0; // We will return how manu billers parsed
		for(Elements::const_iterator class_it = classes->begin();class_it != classes->end(); ++class_it) {
			if((*class_it)->GetName()=="ResponseCode") {
				const string value = (*class_it)->GetValue();
				logfmt(FLOG_MAX,"Parsed ResponseCode: %s", value.c_str());
				if (atoi(value.c_str())!=90000) {
					ret = -3; // NOT SUCCESSFUL
					break;
				}
			} else if ((*class_it)->GetName()=="PaymentItemList") {
				// Iterate payment items
				const Elements* items = (*class_it)->GetChildren();
				if (items!=0) {
					for(Elements::const_iterator items_it = items->begin();items_it != items->end(); ++items_it) {
						if((*items_it)->GetName()=="PaymentItem") {
							// Parse payment item
							const Elements* data = (*items_it)->GetChildren();
							if (data!=0) {
								for (Elements::const_iterator data_it = data->begin();data_it != data->end(); ++data_it) {
									const string key = (*data_it)->GetName();
									const string val = (*data_it)->GetValue();
									saveData[key.c_str()] = val.c_str();
								}
								// Save data
								/*
								hash_map<const char*, const char*, hash<const char*>, eqstr>::iterator pointer;
								for (pointer = saveData.begin();pointer!=saveData.end();++pointer) {
									//logfmt(FLOG_MAX, "'%s' => '%s'", pointer->first, pointer->second);
								}
								*/
								if (save!=NULL) {
									save ("interswitch_biller_payment_items", saveData);
								}
								ret++;
							} else {
								logfmt(FLOG_MAX,"Empty payment item node?");
							}
						}
					}
				} else {
					logfmt(FLOG_MAX,"Empty biller payment item list?");
				}
			} else {
				logfmt(FLOG_MAX,"Skipped element: %s", (*class_it)->GetName().c_str());
			}
		}
	} else {
		logfmt(FLOG_MAX,"Empty response?");
	}
	return 0;
}
/*****************************************************************************/
int ParseInterswitchGetBillerCategoriesResponse(const char *xmlstring,long(*save)(hash_map<const char*, const char*, hash<const char*>, eqstr>)) { //(long, char*, long, char*, char*)) {

	logfmt(FLOG_MAX,"int ParseInterswitchGetBillerCategorisResponse(const char *xmlstring,long(*save)(long, char*, long, char*, char*))");

logfmt(FLOG_MAX,"*** NOT IMPLEMENTED!!! ***");
logfmt(FLOG_MAX, xmlstring);

	logfmt(FLOG_MAX,"/int ParseInterswitchGetBillerCategoriesResponse(const char *xmlstring,long(*save)(long, char*, long, char*, char*))");
	return 0;
}
/*****************************************************************************/
string ParseInterswitchResponse(const char *xmlstring,const char *what,char *response, char *responseCode) {

//  <?xml version="1.0" encoding="utf-8" ?><Response><ResponseCode>90091</ResponseCode><MAC>983A3924883A8B66AEB902E9790BCDE1D8191377E481E20343A4E24954D2BFB528E44F4A9844F4DC681F8ECF9E1A9B9CCC505763D78D1002162B4B3EEEC013AD</MAC><TransactionDate>14/May/2010 06:55:14</TransactionDate><TransactionReference>PAYLID|LOC|CA|ZIB|AC|1405100655|00000001</TransactionReference><TransferCode></TransferCode><Pin></Pin></Response>
  using namespace SimpleXMLParser;

#ifdef TEST
  cout << "RAW: " << xmlstring << endl;
#endif

  XmlParser parser;
  const Element& root = parser.Parse(xmlstring,strlen(xmlstring));

  if (root.GetName()!="Response") {
    logfmt(FLOG_MAX,"Unknown XML response");
    return "";
  }

  string ret = ""; // Empty result cryptogram error
  //char *transactionReference = NULL;
  string transactionReference;

  const Elements* classes = root.GetChildren();
  if(classes != 0) {
    for(Elements::const_iterator class_it = classes->begin();class_it != classes->end(); ++class_it) {
      if((*class_it)->GetName()=="ResponseCode") {

        const string value = (*class_it)->GetValue();
        logfmt(FLOG_MAX,"Parsed ResponseCode: %s", value.c_str());
        strcpy(responseCode,value.c_str());
        ret = value;

      } else if ((*class_it)->GetName()==what) {

        const string value = (*class_it)->GetValue();
        logfmt(FLOG_MAX, "Parsed '%s' => '%s'", what, value.c_str());

        strcpy(response,value.c_str());
        //transactionReference = (char *)malloc(1+strlen(value.c_str()));
        //strcpy(transactionReference,value.c_str());
        transactionReference = value;

      } else if ((*class_it)->GetName()=="TransactionReference") {

        const string value = (*class_it)->GetValue();
        //transactionReference = (char *)malloc(1+strlen(value.c_str()));
        //strcpy(transactionReference,value.c_str());
        transactionReference = value;

      } else {
        logfmt(FLOG_MAX,"Skipped element: %s", (*class_it)->GetName().c_str());
      }
    }
  }
  if (transactionReference.empty() || transactionReference.length()<8L) {
    logfmt(FLOG_MAX,"Empty or missing TransactionReference");
    // Not a comm. error in some cases (overriden above)
  }

/*
  if (transactionReference) {
    free(transactionReference);
  }
*/
  return ret;
}

/*****************************************************************************/
string interswitch_getBankCodes(const char *endpoint, const char *tid, char *status) {
	return "";
}

/*****************************************************************************/
int my_soap_ssl_client_context(BasicHttpBinding_USCOREQuickTellerServiceProxy *q) {
   logfmt(FLOG_MAX,"int my_soap_ssl_client_context(BasicHttpBinding_USCOREQuickTellerServiceProxy *q)");
   int context = 0;

   logfmt(FLOG_MAX,"interswitch_ssl_version=%d", interswitch_ssl_version);

// SOAP_SSL_DEFAULT|SOAP_SSL_SKIP_HOST_CHECK|SOAP_SSL_ALLOW_EXPIRED_CERTIFICATE,
	if (interswitch_ssl_version>0) {
		context = soap_ssl_client_context(q,
   SOAP_SSL_DEFAULT|SOAP_SSL_SKIP_HOST_CHECK|SOAP_SSL_ALLOW_EXPIRED_CERTIFICATE,
   interswitch_ssl_keyfile,	/* keyfile: required only when client must authenticate to server (see SSL docs on how to obtain this file) */
   interswitch_ssl_password,	 /* password to read the key file (not used with GNUTLS) */
   interswitch_ssl_cacert, /* cacert file to store trusted certificates (needed to verify server) */
   NULL,	 /* capath to directory with trusted certificates */
   NULL	 /* if randfile!=NULL: use a file with random data to seed randomness */
	);
	} else {
		context = soap_ssl_client_context(q,SOAP_SSL_SKIP_HOST_CHECK|SOAP_SSL_ALLOW_EXPIRED_CERTIFICATE|SOAP_SSL_NO_AUTHENTICATION,NULL,NULL,NULL,NULL,NULL);
	}
   logfmt(FLOG_MAX,"/int my_soap_ssl_client_context(BasicHttpBinding_USCOREQuickTellerServiceProxy *q)");
   return context;
}


/*****************************************************************************/
long interswitch_getBillers(const char *endpoint, const char *tid, int billerId, int categoryId, int channelId, const char *billerName, char *error, long(*save)(hash_map<const char*, const char*, hash<const char*>, eqstr>)) { //(long, char*, long, char*, char*)) {
	//plog->SetFileName( PREFIX"/logs/SendMoneyInterswitch.log" );
	logfmt( FLOG_MAX, "long interswitch_getBillers(...)" );

	logfmt( FLOG_MAX, "endpoint=%s", endpoint );

	string status = "Unknown error";
	// Check SSL configuration
	if (interswitch_ssl_configured!=1) {
		status = "SSL is not configured";
		strncpy(error,status.c_str(),strlen(error));
		return -1L;
	}

	soap_ssl_init(); /* init OpenSSL (just once) */


	//BasicHttpBinding_USCOREQuickTellerServiceProxy *q = new BasicHttpBinding_USCOREQuickTellerServiceProxy();
	//q->soap_endpoint = endpoint;
	BasicHttpBinding_USCOREQuickTellerServiceProxy q;
	q.soap_endpoint = endpoint;
	_interswitch__GetBillers *interswitch__GetBillers = new _interswitch__GetBillers();
	_interswitch__GetBillersResponse *interswitch__GetBillersResponse = new _interswitch__GetBillersResponse();

  char d[32];

	string xmlParams = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\
<SearchCriteria>";
	xmlParams += "<TerminalId>";
  xmlParams += tid; // PLD
  xmlParams += "</TerminalId>";
	if (billerId>0) {
		xmlParams += "<BillerId>";
		sprintf(d, "%ld", billerId);
		xmlParams += d;
		xmlParams += "</BillerId>";
	}
	if (categoryId>0) {
		xmlParams += "<CategoryId>";
		sprintf(d, "%ld", categoryId);
		xmlParams += d;
		xmlParams += "</CategoryId>";
	}
	if (channelId>0) {
		xmlParams += "<ChannelId>";
		sprintf(d, "%ld", channelId);
		xmlParams += d;
		xmlParams += "</ChannelId>";
	}
	if (billerName!=NULL && strlen(billerName)>0) {
		xmlParams += "<BillerName>";
		xmlParams += billerName;
		xmlParams += "</BillerName>";
	}
	xmlParams += "</SearchCriteria>";

 logfmt( FLOG_MAX, "XML SENT-> %s", xmlParams.c_str());

	interswitch__GetBillers->xmlParams = &xmlParams;

	int context = my_soap_ssl_client_context(&q);
	logfmt( FLOG_MAX, "my_soap_ssl_client_context(q)=%d", context);
	if (context) {
		soap_print_fault(&q, stderr);
		status = "Cannot initalize SOAP/SSL";
		strncpy(error,status.c_str(),strlen(error));
/*
 FILE* pFile = fopen("/tmp/soap_debug.log", "a");
 soap_print_fault(&q, pFile);
 fclose(pFile); */
	delete interswitch__GetBillers;
	delete interswitch__GetBillersResponse;
	//delete q;

			return -1L;
		}

   	long soap_result = SOAP_ERR;
   	try {
			soap_result = q.GetBillers(interswitch__GetBillers, interswitch__GetBillersResponse);

   	} catch (...) {
			status = "Proxy exception";
    }
logfmt( FLOG_MAX, "result = %ld", soap_result ); ////////////////////////////

   	if (soap_result == SOAP_OK) {
			char response[BUFSIZE];
			memset(response,0,BUFSIZE);

			soap_result = ParseInterswitchGetBillersResponse(interswitch__GetBillersResponse->GetBillersResult->c_str(),save);
			//logfmt(FLOG_MAX, "Result: %s", interswitch__GetBillersResponse->GetBillersResult->c_str());
			status = response;
   	} else if (soap_result < 30) {
//			logfmt(FLOG_MAX, "BAD Result: %s", interswitch__GetBillersResponse->GetBillersResult->c_str());
			if (&q!=NULL && q.soap_fault_string()!=NULL) {
	   		status = "Fault string: ";
				status += q.soap_fault_string();
			}
			if (&q!=NULL && q.soap_fault_detail()) {
   	    	status += "Fault detail: ";
					status += q.soap_fault_detail();
			}
			if (&q==NULL) {
	   		status = "Bad proxy";
			} else {
	   		//cout << "Unknown error: " << result << endl;
			}
			soap_result = -1L;
		} else {
			logfmt( FLOG_MAX, "BAD result = %ld", soap_result );
 FILE* pFile = fopen("/tmp/soap_debug.log", "a");
 soap_print_fault(&q, pFile);
 fclose(pFile);
 soap_result = -1L;
		}
	delete interswitch__GetBillers;
	delete interswitch__GetBillersResponse;
	/* if (result<30 && q!=NULL) {
		// The object gets corrupted when there is a HTTP error
		// result<30 valid SOAP responses from http://www.cs.fsu.edu/~engelen/stdsoap2.3.8.h
		delete q;
	} */
	strncpy(error,status.c_str(),strlen(error));
	return soap_result;
}

/*****************************************************************************/
long interswitch_getBillerPaymentItems(const char *endpoint, const char *tid, int billerId, char *error, long(*save)(const char *, hash_map<const char*, const char*, hash<const char*>, eqstr>)) { //(long, char*, long, char*, char*)) {
	//plog->SetFileName( PREFIX"/logs/SendMoneyInterswitch.log" );
	logfmt( FLOG_MAX, "long interswitch_getBillerPaymentItems(...)" );

	logfmt( FLOG_MAX, "endpoint=%s", endpoint );

	string status = "Unknown error";
	// Check SSL configuration
	if (interswitch_ssl_configured!=1) {
		status = "SSL is not configured";
		strncpy(error,status.c_str(),strlen(error));
		return -1L;
	}

	soap_ssl_init(); /* init OpenSSL (just once) */


	//BasicHttpBinding_USCOREQuickTellerServiceProxy *q = new BasicHttpBinding_USCOREQuickTellerServiceProxy();
	//q->soap_endpoint = endpoint;
	BasicHttpBinding_USCOREQuickTellerServiceProxy q;
	q.soap_endpoint = endpoint;
	_interswitch__GetBillerPaymentItems *interswitch__GetBillerPaymentItems = new _interswitch__GetBillerPaymentItems();
	_interswitch__GetBillerPaymentItemsResponse *interswitch__GetBillerPaymentItemsResponse = new _interswitch__GetBillerPaymentItemsResponse();

  char d[32];

	string xmlParams = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\
<SearchCriteria>";
	xmlParams += "<TerminalId>";
  xmlParams += tid; // PLD
  xmlParams += "</TerminalId>";
	if (billerId>0) {
		xmlParams += "<BillerId>";
		sprintf(d, "%ld", billerId);
		xmlParams += d;
		xmlParams += "</BillerId>";
	}
	xmlParams += "</SearchCriteria>";

 logfmt( FLOG_MAX, "XML SENT-> %s", xmlParams.c_str());

	interswitch__GetBillerPaymentItems->xmlParams = &xmlParams;

	int context = my_soap_ssl_client_context(&q);
	logfmt( FLOG_MAX, "my_soap_ssl_client_context(q)=%d", context);
	if (context) {
		soap_print_fault(&q, stderr);
		status = "Cannot initalize SOAP/SSL";
		strncpy(error,status.c_str(),strlen(error));
		delete interswitch__GetBillerPaymentItems;
		delete interswitch__GetBillerPaymentItemsResponse;
		//delete q;

			return -1L;
		}

   	long soap_result = SOAP_ERR;
   	try {
			soap_result = q.GetBillerPaymentItems(interswitch__GetBillerPaymentItems, interswitch__GetBillerPaymentItemsResponse);

   	} catch (...) {
			status = "Proxy exception";
    }
logfmt( FLOG_MAX, "result = %ld", soap_result ); ////////////////////////////

   	if (soap_result == SOAP_OK) {
			char response[BUFSIZE];
			memset(response,0,BUFSIZE);
			soap_result = ParseInterswitchGetBillerPaymentItemsResponse(interswitch__GetBillerPaymentItemsResponse->GetBillerPaymentItemsResult->c_str(),save);
			//logfmt(FLOG_MAX, "Result: %s", interswitch__GetBillerPaymentItemsResponse->GetBillerPaymentItemsResult->c_str());
			status = response;
   	} else if (soap_result < 30) {
//			logfmt(FLOG_MAX, "BAD Result: %s", interswitch__GetBillerPaymentItemsResponse->GetBillerPaymentItemsResult->c_str());
			if (&q!=NULL && q.soap_fault_string()!=NULL) {
	   		status = "Fault string: ";
				status += q.soap_fault_string();
			}
			if (&q!=NULL && q.soap_fault_detail()) {
   	    	status += "Fault detail: ";
					status += q.soap_fault_detail();
			}
			if (&q==NULL) {
	   		status = "Bad proxy";
			} else {
	   		//cout << "Unknown error: " << result << endl;
			}
			soap_result = -1L;
		} else {
			logfmt( FLOG_MAX, "BAD result = %ld", soap_result );
			soap_result = -1L;
		}
	delete interswitch__GetBillerPaymentItems;
	delete interswitch__GetBillerPaymentItemsResponse;
	strncpy(error,status.c_str(),strlen(error));
	return soap_result;
}

/*****************************************************************************/
long interswitch_getBillerCategories(const char *endpoint, char *error, long(*save)(hash_map<const char*, const char*, hash<const char*>, eqstr>)) { //(long, char*, long, char*, char*)) {
	//plog->SetFileName( PREFIX"/logs/SendMoneyInterswitch.log" );
	logfmt( FLOG_MAX, "long interswitch_getBillerCategories(...)" );

	logfmt( FLOG_MAX, "endpoint=%s", endpoint );

	string status = "Unknown error";
	// Check SSL configuration
	if (interswitch_ssl_configured!=1) {
		status = "SSL is not configured";
		strncpy(error,status.c_str(),strlen(error));
		return -1L;
	}

	soap_ssl_init(); /* init OpenSSL (just once) */


	//BasicHttpBinding_USCOREQuickTellerServiceProxy *q = new BasicHttpBinding_USCOREQuickTellerServiceProxy();
	//q->soap_endpoint = endpoint;
	BasicHttpBinding_USCOREQuickTellerServiceProxy q;
	q.soap_endpoint = endpoint;
	_interswitch__GetBillerCategories *interswitch__GetBillerCategories = new _interswitch__GetBillerCategories();
	_interswitch__GetBillerCategoriesResponse *interswitch__GetBillerCategoriesResponse = new _interswitch__GetBillerCategoriesResponse();

  char d[32];

	int context = my_soap_ssl_client_context(&q);
	logfmt( FLOG_MAX, "my_soap_ssl_client_context(q)=%d", context);
	if (context) {
		soap_print_fault(&q, stderr);
		status = "Cannot initalize SOAP/SSL";
		strncpy(error,status.c_str(),strlen(error));
		delete interswitch__GetBillerCategoriesResponse;
		delete interswitch__GetBillerCategories;
		//delete q;
			return -1L;
		}

   	long soap_result = SOAP_ERR;
   	try {
   	
			soap_result = q.GetBillerCategories(interswitch__GetBillerCategories, interswitch__GetBillerCategoriesResponse);

   	} catch (...) {
			status = "Proxy exception";
    }
logfmt( FLOG_MAX, "result = %ld", soap_result ); ////////////////////////////

   	if (soap_result == SOAP_OK) {
			char response[BUFSIZE];
			memset(response,0,BUFSIZE);
			soap_result = ParseInterswitchGetBillerCategoriesResponse(interswitch__GetBillerCategoriesResponse->GetBillerCategoriesResult->c_str(),save);
			status = response;
   	} else if (soap_result < 30) {
			if (&q!=NULL && q.soap_fault_string()!=NULL) {
	   		status = "Fault string: ";
				status += q.soap_fault_string();
			}
			if (&q!=NULL && q.soap_fault_detail()) {
   	    	status += "Fault detail: ";
					status += q.soap_fault_detail();
			}
			if (&q==NULL) {
	   		status = "Bad proxy";
			} else {
	   		//cout << "Unknown error: " << result << endl;
			}
			soap_result = -1L;
		} else {
			logfmt( FLOG_MAX, "BAD result = %ld", soap_result );
			soap_result = -1L;
		}
	delete interswitch__GetBillerCategories;
	delete interswitch__GetBillerCategoriesResponse;

	strncpy(error,status.c_str(),strlen(error));
	logfmt( FLOG_MAX, "long interswitch_getBillerCategories(...)" );
	return soap_result;
}

/*****************************************************************************/
string interswitch_queryTransaction(const char *endpoint, const char *tid, const char *transferCode, const char *requestReference, char *error, char *transactionResponseCode) {

	//plog->SetFileName( PREFIX"/logs/SendMoneyInterswitch.log" );
	logfmt( FLOG_MAX, "long interswitch_getBillerCategories(...)" );
	logfmt( FLOG_MAX, "endpoint=%s", endpoint );
	
	string status = "Unknown error";
	// Check SSL configuration
	if (interswitch_ssl_configured!=1) {
		status = "SSL is not configured";
		strsafecpy(error,status.c_str(),SAFESTRING_COMMON_BUFFER_SIZE);
		return "-1";
	}
	soap_ssl_init(); /* init OpenSSL (just once) */

	//BasicHttpBinding_USCOREQuickTellerServiceProxy *q = new BasicHttpBinding_USCOREQuickTellerServiceProxy();
	//q->soap_endpoint = endpoint;
	BasicHttpBinding_USCOREQuickTellerServiceProxy q;
	q.soap_endpoint = endpoint;
	_interswitch__QueryTransaction *interswitch__QueryTransaction = new _interswitch__QueryTransaction();
	_interswitch__QueryTransactionResponse *interswitch__QueryTransactionResponse = new _interswitch__QueryTransactionResponse();

	string xmlParams = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\
<RequestDetails>\
    <TerminalId>";
	xmlParams += tid; // PLD
	xmlParams += "</TerminalId>";
	if (atoi(transferCode)>1) {
		xmlParams += "<TransferCode>";
		xmlParams += transferCode;
		xmlParams += "</TransferCode>";
	}
	xmlParams += "<PaymentReference>";
	xmlParams += requestReference;
	xmlParams += "</PaymentReference>";
	xmlParams += "</RequestDetails>";

	logfmt( FLOG_MAX, "XML SENT-> %s", xmlParams.c_str());

	interswitch__QueryTransaction->xmlParams = &xmlParams;

	if (my_soap_ssl_client_context(&q)) {
		soap_print_fault(&q, stderr);
		status = "Cannot initalize SOAP/SSL";
		strsafecpy(error,status.c_str(),SAFESTRING_COMMON_BUFFER_SIZE);
		delete interswitch__QueryTransaction;
		delete interswitch__QueryTransaction;
		//delete q;
		return "-1";
	}
	string result = "";
	long soap_result = SOAP_ERR;
	try {
		soap_result = q.QueryTransaction(interswitch__QueryTransaction, interswitch__QueryTransactionResponse);
	} catch (...) {
		status = "Proxy exception";
	}
	if (soap_result == SOAP_OK) {
		char response[SAFESTRING_COMMON_BUFFER_SIZE], response_code[SAFESTRING_COMMON_BUFFER_SIZE];
		memset(response,0,SAFESTRING_COMMON_BUFFER_SIZE);
		memset(response_code,0,SAFESTRING_COMMON_BUFFER_SIZE);

		result = ParseInterswitchResponse(interswitch__QueryTransactionResponse->QueryTransactionResult->c_str(),"TransactionResponseCode",response,response_code);
		//logfmt(FLOG_MAX, "Result: %s", interswitch__QueryTransactionResponse->QueryTransactionResult->c_str());
		strsafecpy(transactionResponseCode, response_code, SAFESTRING_COMMON_BUFFER_SIZE);
		//strncpy(transactionResponseCode,response,SAFESTRING_COMMON_BUFFER_SIZE);
		status = response;
	} else if (soap_result<30) {
		logfmt(FLOG_MAX, "BAD Result: %s", interswitch__QueryTransactionResponse->QueryTransactionResult->c_str());
		if (&q!=NULL && q.soap_fault_string()!=NULL) {
			status = "Fault string: ";
			status += q.soap_fault_string();
		}
		if (&q!=NULL && q.soap_fault_detail()) {
			status += "Fault detail: ";
			status += q.soap_fault_detail();
		}
		if (&q==NULL) {
			status = "Bad proxy";
		} else {
			//cout << "Unknown error: " << result << endl;
		}
	} else {
		logfmt(FLOG_MAX, "BAD Result: %ld", soap_result);
	}

	delete interswitch__QueryTransaction;
	delete interswitch__QueryTransactionResponse;
	//delete q;
	strncpy(error,status.c_str(),SAFESTRING_COMMON_BUFFER_SIZE);
	logfmt(FLOG_MAX, "Response: %s", error);
	return result;
}

/*****************************************************************************/
long interswitch_getBalance(const char *endpoint, const char *tid, const char *mkey, const char *pin, char *error) {
	return -1;
}

/*****************************************************************************/
string interswitch_transferFunds(const char *endpoint, const char *tid, const char *mkey, const char *pin, char *error, const char *account, const char *uniqueRef, const char *bankCode, long currency, long amount, CVars trans_info) {


	//plog->SetFileName( PREFIX"/logs/SendMoneyInterswitch.log" );

	string status = "Unknown error";
	// Check SSL configuration
  if (interswitch_ssl_configured!=1) {
    status = "SSL is not configured";
    strncpy(error,status.c_str(),strlen(error));
    return "-1";
  }
	soap_ssl_init(); /* init OpenSSL (just once) */
	BasicHttpBinding_USCOREQuickTellerServiceProxy q; // = new BasicHttpBinding_USCOREQuickTellerServiceProxy();
	q.soap_endpoint = endpoint;
	_interswitch__DoTransfer *interswitch__DoTransfer = new _interswitch__DoTransfer();
	_interswitch__DoTransferResponse *interswitch__DoTransferResponse = new _interswitch__DoTransferResponse();

//     <MAC>ACB7AA183D50289B2149D441F2C888C2A3A1AEE7EFCE80838DD58BE83A243AB3E4E87D55D7788CA29A32EA27A93678131255211A8A297266A74426985864AAC9</MAC>\
   // <MAC>100000566CA100000566ACNG</MAC>
// InitiatingAmount, InitiatingCurrencyCode, InitiatingPaymentMethodCode, TerminatingAmount, TerminatingCurrencyCode, TerminatingPaymentMethodCode, TerminatingCountryCode
	char d[32];
	string data = "";
	sprintf(d, "%ld", amount);
	data += d;
	sprintf(d, "%03ld", currency);
	data += d;
	data += "CA";
	sprintf(d, "%ld", amount);
	data += d;
	sprintf(d, "%03ld", currency);
	data += d;
	data += "AC";
	data += "NG";
	logfmt(FLOG_MAX, "DTA=%s", data.c_str());
	string mac = hash_sha512_cpp(data);
	logfmt(FLOG_MAX, "MAC=%s", mac.c_str());


/*
		//Sender
		trans_info["sender_firstname"]="";
		trans_info["sender_lastname"]="";
		trans_info["senders_email"]="";
		trans_info["phone"]="";

		//Recipient
		trans_info["recipient_name"]="";
*/

	string xmlParams = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\
<RequestDetails >\
    <InitiatingEntityCode>";
	xmlParams += tid; // PLD
	xmlParams += "</InitiatingEntityCode>\
    <MAC>";
	xmlParams += mac; // ACB7AA183D50289B2149D441F2C888C2A3A1AEE7EFCE80838DD58BE83A243AB3E4E87D55D7788CA29A32EA27A93678131255211A8A297266A74426985864AAC9
	xmlParams += "</MAC><TransferCode>";
	xmlParams += uniqueRef;
	xmlParams += "</TransferCode>\
    <Sender>\
        <Lastname>";
        xmlParams +=trans_info["sender_lastname"].c_str();
        xmlParams += "</Lastname>\
        <Othernames>";
         xmlParams +=trans_info["sender_firstname"].c_str();
         xmlParams += "</Othernames>\
         <Email>";
          xmlParams +=trans_info["senders_email"].c_str();
          xmlParams += "</Email>\
        <Phone>";
        xmlParams +=trans_info["senders_phone"].c_str();
        xmlParams += "</Phone>\
    </Sender>\
    <Beneficiary>\
        <Lastname>";
         xmlParams +=trans_info["recipient_name"].c_str();
        xmlParams += "</Lastname>\
        <Othernames>";
        xmlParams +=trans_info["recipient_name"].c_str();
         xmlParams += "</Othernames>\
        <Email>";
         xmlParams +=trans_info["rec_email"].c_str();
         xmlParams += "</Email>\
        <Phone>";
         xmlParams +=trans_info["rec_phone"].c_str();
        xmlParams += "</Phone>\
    </Beneficiary>\
    <Initiation>\
        <Reason></Reason>\
        <Amount>";
	sprintf(d, "%ld", amount);
	xmlParams += d; // 1000000
	xmlParams += "</Amount>\
        <Channel>7</Channel>\
        <PaymentMethodCode>CA</PaymentMethodCode>\
        <CurrencyCode>";
	sprintf(d, "%03ld", currency);
	xmlParams += d; // 566 - NRN - Naira
	xmlParams += "</CurrencyCode>\
	<Processor>\
		<Lastname></Lastname>\
		<Othernames ></Othernames>\
	</Processor>\
	<DepositSlip></DepositSlip>\
    </Initiation>\
    <Termination>\
        <PaymentMethodCode>AC</PaymentMethodCode>\
        <Amount>";
	sprintf(d, "%ld", amount);
	xmlParams += d; // 1000000
	xmlParams += "</Amount>\
        <CurrencyCode>";
	sprintf(d, "%03ld", currency);
	xmlParams += d; // 566 - NRN - Naira
	xmlParams += "</CurrencyCode>\
        <CountryCode>NG</CountryCode>\
        <AccountReceivable>\
            <AccountNumber>";
	xmlParams += account;
	xmlParams += "</AccountNumber>\
            <AccountType>20</AccountType>\
            <BankCBNCode>";
///-----> leave blank for now	xmlParams += bankCode; // 057
	xmlParams += "</BankCBNCode>\
        </AccountReceivable>\
        <CashReceivable> \
			<TypeCode>LO</TypeCode> \
			<EntityCode>";
				xmlParams += bankCode;   // moved here as recomended
			xmlParams += "</EntityCode> \
			<EntityLocationCode>ZFD1234</EntityLocationCode> \
			<StateCode>LAG</StateCode> \
			<Identification> \
				<TypeCode>DL</TypeCode> \
				<Description>1234567</Description> \
			</Identification> \
			<Pin>BA3253876AED6BC22D4A6FF53D8406C6AD864195ED144AB5C87621B6C233B548BAEAE6956DF346EC8C17F5EA10F35EE3CBC514797ED7DDD3145464E2A0BAB413</Pin> \
        </CashReceivable> \
    </Termination>\
</RequestDetails>";

  logfmt( FLOG_MAX, "XML SENT-> %s", xmlParams.c_str());

	interswitch__DoTransfer->xmlParams = &xmlParams;

	if (my_soap_ssl_client_context(&q)) {

			soap_print_fault(&q, stderr);
			status = "Cannot initalize SOAP/SSL";
			strncpy(error,status.c_str(),strlen(error));

	delete interswitch__DoTransfer;
	delete interswitch__DoTransferResponse;
	//delete q;

			return "-1";
		}

   	string result = "";
   	long soap_result = SOAP_ERR;
   	try {
			soap_result = q.DoTransfer(interswitch__DoTransfer, interswitch__DoTransferResponse);
   	} catch (...) {
			status = "Proxy exception";
    }
   	if (soap_result == SOAP_OK) {
			char response[BUFSIZE], response_code[BUFSIZE];
			memset(response,0,BUFSIZE);
			memset(response_code,0,BUFSIZE);
			result = ParseInterswitchResponse(interswitch__DoTransferResponse->DoTransferResult->c_str(),"TransactionReference",response,response_code);
			logfmt(FLOG_MAX,"Result: %s", interswitch__DoTransferResponse->DoTransferResult->c_str());
			status = "";
			status += response;
		} else {
logfmt(FLOG_MAX, "About to crash!!!\n\n\n");
//logfmt(FLOG_MAX, "BAD Result: %s", interswitch__DoTransferResponse->DoTransferResult->c_str());

			if (&q!=NULL && q.soap_fault_string()!=NULL) {
	   		status = "Fault string: ";
				status += q.soap_fault_string();
			}
			if (&q!=NULL && q.soap_fault_detail()) {
   	    	status += "Fault detail: ";
					status += q.soap_fault_detail();
			}
			if (&q==NULL) {
	   		status = "Bad proxy";
			} else {
	   		//cout << "Unknown error: " << result << endl;
			}
		}


	delete interswitch__DoTransfer;
	delete interswitch__DoTransferResponse;
	//delete q;
	strncpy(error,status.c_str(),strlen(error));
	return result;
}

/*****************************************************************************/
string interswitch_doTransfer(const char *endpoint, const char *tid, CVars trans_info, char *error) {

	//plog->SetFileName( PREFIX"/logs/SendMoneyInterswitch.log" );

	string status = "Unknown error";
	// Check SSL configuration
	if (interswitch_ssl_configured!=1) {
		status = "SSL is not configured";
		strsafecpy(error,status.c_str(),SAFESTRING_COMMON_BUFFER_SIZE);
		return "-1";
	}
	soap_ssl_init(); /* init OpenSSL (just once) */
	BasicHttpBinding_USCOREQuickTellerServiceProxy q; // = new BasicHttpBinding_USCOREQuickTellerServiceProxy();
	q.soap_endpoint = endpoint;
	_interswitch__DoTransfer *interswitch__DoTransfer = new _interswitch__DoTransfer();
	_interswitch__DoTransferResponse *interswitch__DoTransferResponse = new _interswitch__DoTransferResponse();

//     <MAC>ACB7AA183D50289B2149D441F2C888C2A3A1AEE7EFCE80838DD58BE83A243AB3E4E87D55D7788CA29A32EA27A93678131255211A8A297266A74426985864AAC9</MAC>\
   // <MAC>100000566CA100000566ACNG</MAC>
// InitiatingAmount, InitiatingCurrencyCode, InitiatingPaymentMethodCode, TerminatingAmount, TerminatingCurrencyCode, TerminatingPaymentMethodCode, TerminatingCountryCode
	char d[32];
	string data = "";
	data += trans_info["InitiatingAmount"].c_str();
	data += trans_info["InitiatingCurrencyCode"].c_str(); // NG 
	data += trans_info["InitiatingPaymentMethodCode"].c_str(); // CA
	data += trans_info["TerminatingAmount"].c_str();
	data += trans_info["TerminatingCurrencyCode"].c_str(); // NGN
	data += trans_info["TerminatingPaymentMethodCode"].c_str(); // AC
	data += trans_info["TerminatingCountryCode"].c_str(); // NG

	/* sprintf(d, "%03ld", currency);
	data += d;
	data += "CA";
	sprintf(d, "%ld", amount);
	data += d;
	sprintf(d, "%03ld", currency);
	data += d;
	data += "AC";
	data += "NG"; */
	logfmt(FLOG_MAX, "DTA=%s", data.c_str());
	string mac = hash_sha512_cpp(data);
	logfmt(FLOG_MAX, "MAC=%s", mac.c_str());

/*
		//Sender
		trans_info["sender_firstname"]="";
		trans_info["sender_lastname"]="";
		trans_info["senders_email"]="";
		trans_info["phone"]="";

		//Recipient
		trans_info["recipient_name"]="";
*/

	string xmlParams = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\
<RequestDetails >\
    <InitiatingEntityCode>";
	xmlParams += tid; // PLD
	xmlParams += "</InitiatingEntityCode>\
    <MAC>";
	xmlParams += mac; // ACB7AA183D50289B2149D441F2C888C2A3A1AEE7EFCE80838DD58BE83A243AB3E4E87D55D7788CA29A32EA27A93678131255211A8A297266A74426985864AAC9
	xmlParams += "</MAC>\
    <TransferCode>";
	sprintf(d, "%s", trans_info["TransferCode"].c_str());
	logfmt(FLOG_MAX, "TransferCode=%s", d);
	xmlParams += d;
	xmlParams += "</TransferCode>\
    <Sender>\
        <Lastname>";
        xmlParams += trans_info["SenderLastname"].c_str();
        xmlParams += "</Lastname><Email>ses66181+sender@gmail.com</Email>\		
        <Othernames>";
         xmlParams += trans_info["SenderOthernames"].c_str();
         xmlParams += "</Othernames>";
         /*
         <Email>";
          xmlParams += trans_info["SenderEmail"].c_str();
          xmlParams += "</Email>\
        <Phone>";
        xmlParams += trans_info["SenderPhone"].c_str();
        xmlParams += "</Phone>";
        */
        xmlParams += "\
    </Sender>\
    <Beneficiary>\
        <Lastname>";
         xmlParams += trans_info["BeneficiaryLastname"].c_str();
        xmlParams += "</Lastname><Email>ses66181+reciver@gmail.com</Email>\
        <Othernames>";
        xmlParams += trans_info["BeneficiaryOthernames"].c_str();
         xmlParams += "</Othernames>";
         /*
        <Email>";
         xmlParams += trans_info["BeneficiaryEmail"].c_str();
         xmlParams += "</Email>\
        <Phone>";
         xmlParams += trans_info["BeneficiaryPhone"].c_str();
        xmlParams += "</Phone>";
        */
        xmlParams += "\
    </Beneficiary>\
    <Initiation>\
        <Reason></Reason>\
        <Amount>";
        xmlParams += trans_info["InitiatingAmount"].c_str();
        /*
	sprintf(d, "%ld", amount);
	xmlParams += d; // 1000000
	*/
	xmlParams += "</Amount>\
        <Channel>";
        xmlParams += trans_info["InitiatingChannel"].c_str();
        xmlParams += "</Channel>\
        <PaymentMethodCode>";
        xmlParams += trans_info["InitiatingPaymentMethodCode"].c_str();
        xmlParams += "</PaymentMethodCode>\
        <CurrencyCode>";
        xmlParams += trans_info["InitiatingCurrencyCode"].c_str();
        /*
	sprintf(d, "%03ld", currency);
	xmlParams += d; // 566 - NRN - Naira
	*/
	xmlParams += "</CurrencyCode>\
    </Initiation>\
    <Termination>\
        <PaymentMethodCode>";
        xmlParams += trans_info["TerminatingPaymentMethodCode"].c_str();
        xmlParams += "</PaymentMethodCode>\
        <Amount>";
        xmlParams += trans_info["TerminatingAmount"].c_str();
        /*
	sprintf(d, "%ld", amount);
	xmlParams += d; // 1000000
	*/
	xmlParams += "</Amount>\
        <CurrencyCode>";
        xmlParams += trans_info["TerminatingCurrencyCode"].c_str();
        /*
	sprintf(d, "%03ld", currency);
	xmlParams += d; // 566 - NRN - Naira
	*/
	xmlParams += "</CurrencyCode>\
        <CountryCode>";
        xmlParams += trans_info["TerminatingCountryCode"].c_str();
        xmlParams += "</CountryCode>\
        <AccountReceivable>\
            <AccountNumber>";
	xmlParams += trans_info["TerminatingAccountNumber"].c_str();
	xmlParams += "</AccountNumber>\
            <AccountType>";
        xmlParams += trans_info["TerminatingAccountType"].c_str();
        xmlParams += "</AccountType>\
            <EntityCode>";
///-----> leave blank for now	xmlParams += bankCode; // 057
	xmlParams += trans_info["TerminatingEntityCode"].c_str();
	xmlParams += "</EntityCode>\
        </AccountReceivable>";
        /*
        <CashReceivable> \
			<TypeCode>LO</TypeCode> \
			<EntityCode>";
			xmlParams += trans_info["TerminatingEntityCode"].c_str();   // moved here as recomended
			xmlParams += "</EntityCode> \
			<EntityLocationCode>ZFD1234</EntityLocationCode> \
			<StateCode>LAG</StateCode> \
			<Identification> \
				<TypeCode>DL</TypeCode> \
				<Description>1234567</Description> \
			</Identification> \
			<Pin>BA3253876AED6BC22D4A6FF53D8406C6AD864195ED144AB5C87621B6C233B548BAEAE6956DF346EC8C17F5EA10F35EE3CBC514797ED7DDD3145464E2A0BAB413</Pin> \
        </CashReceivable> \
        */
        xmlParams += "\
    </Termination>\
</RequestDetails>";

  logfmt( FLOG_MAX, "XML SENT-> %s", xmlParams.c_str());

	interswitch__DoTransfer->xmlParams = &xmlParams;

	if (my_soap_ssl_client_context(&q)) {

		soap_print_fault(&q, stderr);
		status = "Cannot initalize SOAP/SSL";
		strncpy(error,status.c_str(),strlen(error));

		delete interswitch__DoTransfer;
		delete interswitch__DoTransferResponse;
		//delete q;

		return "-1";
	}

	string result = "";
	long soap_result = SOAP_ERR;
	try {
		soap_result = q.DoTransfer(interswitch__DoTransfer, interswitch__DoTransferResponse);
	} catch (...) {
			status = "Proxy exception";
	}
 	if (soap_result == SOAP_OK) {
		char response[SAFESTRING_COMMON_BUFFER_SIZE], response_code[SAFESTRING_COMMON_BUFFER_SIZE];
		memset(response,0,SAFESTRING_COMMON_BUFFER_SIZE);
		memset(response_code,0,SAFESTRING_COMMON_BUFFER_SIZE);
		result = ParseInterswitchResponse(interswitch__DoTransferResponse->DoTransferResult->c_str(),"TransactionReference",response,response_code);
		logfmt(FLOG_MAX,"Result: %s", interswitch__DoTransferResponse->DoTransferResult->c_str());
		status = response;
	} else if (soap_result<30) {
		logfmt(FLOG_MAX, "BAD Result: %s", interswitch__DoTransferResponse->DoTransferResult->c_str());
		if (&q!=NULL && q.soap_fault_string()!=NULL) {
			status = "Fault string: ";
			status += q.soap_fault_string();
		}
		if (&q!=NULL && q.soap_fault_detail()) {
			status += "Fault detail: ";
			status += q.soap_fault_detail();
		}
		if (&q==NULL) {
			status = "Bad proxy";
		} else {
			//cout << "Unknown error: " << result << endl;
		}
	} else {
		logfmt(FLOG_MAX, "Bad result: %ld", soap_result);
	}

	delete interswitch__DoTransfer;
	delete interswitch__DoTransferResponse;
	//delete q;
	strsafecpy(error,status.c_str(),SAFESTRING_COMMON_BUFFER_SIZE);
	return result;
}

/*****************************************************************************/
long interswitch_pinChange(const char *tid, const char *mkey, const char *pin, char *error) {
	return -1L;
}

/*****************************************************************************/
//1.7.5 Recharge
//Process Flow
//? Accept payment instrument from customer (cash, debit account, etc)
//? Initiate a SendBillPaymentAdvice message to InterSwitch – Error! Reference
//source not found.
//o In the case of recharge PINs, the PIN would be delivered in the
//response.
//o In the case of direct top-up, the specified customer number would be
//topped up automatically
//Sample Request

//<?xml version="1.0" encoding="utf-8" ?>
//<BillPaymentAdvice>
//	<Amount>450000</Amount>
//	<PaymentCode>10401</PaymentCode>
//	<CustomerMobile>08034567123</CustomerMobile>
//	<CustomerEmail>uabu@yahoo.com</CustomerEmail>
//	<CustomerId>0000000001</CustomerId>
//	<TerminalId>3TPR0001</TerminalId>
//</BillPaymentAdvice>

//Sample Response
//<?xml version="1.0" encoding="utf-8" ?>
//<Response>
//	<ResponseCode>90000</ResponseCode>
//	<MAC> BB292DF9268F05CB9CBBC5E0C13CC1B13ACA34DC </ MAC >
//	<TransactionDate>01/Feb/2009 11:28:02</TransactionDate>
//	<TransactionReference>FZIB|LOC|CA|ZIB|CA|1102101115|1801098909</TransactionReference>
//	<TransferCode>123456</ TransferCode >
//	<Pin>345612349876</ Pin >

/*****************************************************************************/
string interswitch_SendBillPaymentAdvice(const char *endpoint, const char *tid, long amount, const char *paymentCode, long customerId, const char *requestReference, char *error, char *transactionRef, char *customer_mobile,char *customer_email) {
	//plog->SetFileName( PREFIX"/logs/SendMoneyInterswitch.log" );
	logfmt( FLOG_MAX, "long interswitch_SendBillPaymentAdvice(...)" );

	logfmt( FLOG_MAX, "endpoint=%s", endpoint );
/*
	logfmt( logDEBUG, "tid=%s", tid );
	logfmt( logDEBUG, "amount=%ld", amount );
	logfmt( logDEBUG, "paymentCode=%s", paymentCode );
	logfmt( logDEBUG, "customerId=%ld", customerId );
	logfmt( logDEBUG, "requestReference=%s", requestReference );
	logfmt( logDEBUG, "error=%s", error );
	logfmt( logDEBUG, "transactionRef=%s", transactionRef );
	logfmt( logDEBUG, "customer_mobile=%s", customer_mobile );
	logfmt( logDEBUG, "customer_email=%s", customer_email );
//*/
	string status = "Unknown error";
	// Check SSL configuration
	if (interswitch_ssl_configured!=1) {
		status = "SSL is not configured";
		strncpy(error,status.c_str(),strlen(error));
		return "-1";
	}

	soap_ssl_init(); /* init OpenSSL (just once) */


	//BasicHttpBinding_USCOREQuickTellerServiceProxy *q = new BasicHttpBinding_USCOREQuickTellerServiceProxy();
	//q->soap_endpoint = endpoint;
	BasicHttpBinding_USCOREQuickTellerServiceProxy q;
	q.soap_endpoint = endpoint;
	_interswitch__SendBillPaymentAdvice *interswitch__SendBillPaymentAdvice = new _interswitch__SendBillPaymentAdvice();
	_interswitch__SendBillPaymentAdviceResponse *interswitch__SendBillPaymentAdviceResponse = new _interswitch__SendBillPaymentAdviceResponse();

	char d[32];

	string xmlParams = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\
<BillPaymentAdvice>";
		xmlParams += "<Amount>";
		sprintf(d, "%ld", amount);
		xmlParams += d;
		xmlParams += "</Amount>";

		xmlParams += "<PaymentCode>";
		xmlParams += paymentCode;
		xmlParams += "</PaymentCode>";
/*
		xmlParams += "<CustomerMobile>";
		xmlParams += customer_mobile;
		xmlParams += "</CustomerMobile>";
*/
/*
		xmlParams += "<CustomerEmail>ameye@paylid.com</CustomerEmail>";
*/

/**/
		xmlParams += "<CustomerMobile>";
		xmlParams += customer_mobile;
		xmlParams += "</CustomerMobile>";
		xmlParams += "<CustomerEmail>";
		xmlParams += customer_email;
		xmlParams += "</CustomerEmail>";
/**/
		xmlParams += "<CustomerId>";
		xmlParams += customer_mobile;
		sprintf(d, "%ld", customerId);
		//xmlParams += d;
		xmlParams += "</CustomerId>";

		xmlParams += "<TerminalId>";
		xmlParams += tid; // PLD
		xmlParams += "</TerminalId>";

		xmlParams += "<RequestReference>";
		xmlParams += requestReference;
		xmlParams += "</RequestReference>";

	xmlParams += "</BillPaymentAdvice>";

 logfmt( FLOG_MAX, "XML SENT-> %s", xmlParams.c_str());

	interswitch__SendBillPaymentAdvice->xmlParams = &xmlParams;

	int context = my_soap_ssl_client_context(&q);
	logfmt( FLOG_MAX, "my_soap_ssl_client_context(q)=%d", context);
	if (context) {
		soap_print_fault(&q, stderr);
		status = "Cannot initalize SOAP/SSL";
		strncpy(error,status.c_str(),strlen(error));
		delete interswitch__SendBillPaymentAdvice;
		delete interswitch__SendBillPaymentAdviceResponse;
		//delete q;

			return "-1";
		}

   	string result = "";
   	long soap_result = SOAP_ERR;
   	try {
			soap_result = q.SendBillPaymentAdvice(interswitch__SendBillPaymentAdvice, interswitch__SendBillPaymentAdviceResponse);

   	} catch (...) {
			status = "Proxy exception";
    }
logfmt( FLOG_MAX, "result = %ld", soap_result ); ////////////////////////////

   	if (soap_result == SOAP_OK) {
			char response[BUFSIZE], response_code[BUFSIZE];
			memset(response,0,BUFSIZE);
			memset(response_code,0,BUFSIZE);
			strncpy(response,interswitch__SendBillPaymentAdviceResponse->SendBillPaymentAdviceResult->c_str(),BUFSIZE);
			logfmt(FLOG_MAX, "Result: %s", response);
			strcpy(transactionRef, "");
			result = ParseInterswitchResponse(response,"TransactionRef",transactionRef,response_code);
			logfmt(FLOG_MAX, "Result->: %ld", soap_result);
			status = response_code;
   	} else if (soap_result < 30) {
//			logfmt(FLOG_MAX, "BAD Result: %s", interswitch__SendBillPaymentAdviceResponse->SendBillPaymentAdviceResult->c_str());
			if (&q!=NULL && q.soap_fault_string()!=NULL) {
	   		status = "Fault string: ";
				status += q.soap_fault_string();
			}
			if (&q!=NULL && q.soap_fault_detail()) {
   	    	status += "Fault detail: ";
					status += q.soap_fault_detail();
			}
			if (&q==NULL) {
	   		status = "Bad proxy";
			} else {
	   		//cout << "Unknown error: " << result << endl;
			}
		} else {
			logfmt( FLOG_MAX, "BAD result = %ld", soap_result );
		}
	delete interswitch__SendBillPaymentAdvice;
	delete interswitch__SendBillPaymentAdviceResponse;
	strncpy(error,status.c_str(),BUFSIZE);
	
	return result;

}

/*****************************************************************************/
long interswitch_test() {
  // Common
  long ret = 0;
  const char *endpoint = "https://stageserv.interswitchng.com/uat_quicktellerservice/quickteller.svc";
  const char *tid = "PLD";
  const char *mkey = "2D1A2518252A1B1A2A23281F242518212123221D272C1C26";
  const char *pin = "2009";
  // Specific  2D1A2518252A1B1A2A23281F242518212123221D272C1C26
  const char *account = "1110000001"; // "6280513434343444";

	char* status = (char *)malloc(BUFSIZE);
	memset(status,32,BUFSIZE);
	status[BUFSIZE] = '\0';

	char *transCode = (char *)malloc(BUFSIZE);
	memset(transCode, 0, BUFSIZE);
	sprintf(transCode,"123098750"); // ???
logfmt(FLOG_MAX, "LOC 0 ==========================================================");
	// We need to config SSL first
	interswitch_config_ssl(
		"/etc/paylid/paylid_test.pem",
		"password",
		"/etc/paylid/testservices.interswitchng.com.pem",
		0
	);
/**
	logfmt(FLOG_MAX, "==========================================================");
	ret = interswitch_getBillers(endpoint, tid, 0, 0, 0, "", status, NULL);
	logfmt(FLOG_MAX, "Return: %ld",ret);
	logfmt(FLOG_MAX, "Status: %s",status);
//*/

//INSERT INTO interswitch_money_transfer 
//(Fee,InitiatingAmount,InitiatingChannel,InitiatingCurrencyCode,InitiatingEntityCode,InitiatingPaymentMethodCode,TerminatingAccountNumber,TerminatingAccountType,TerminatingAmount,TerminatingCountryCode,TerminatingCurrencyCode,
//TerminatingEntityCode,TerminatingPaymentMethodCode,recipientid,senderid) VALUES 
//('100000','1000000','7','566','044','CA','1234567890','20','1000000','NG','566','057','AC','1','1')
	CVars trans_info;
	// 3MBA0001
	trans_info["Fee"] = "1000";
	trans_info["InitiatingAmount"] = "10000";
	trans_info["InitiatingChannel"] = "7";
	trans_info["InitiatingCurrencyCode"] = "566";
	trans_info["InitiatingEntityCode"] = "044";
	trans_info["InitiatingPaymentMethodCode"] = "CA";
	trans_info["TerminatingAccountNumber"] = "1234567890";
	trans_info["TerminatingAccountType"] = "20";
	trans_info["TerminatingAmount"] = "10000";
	trans_info["TerminatingCountryCode"] = "NG";
	trans_info["TerminatingCurrencyCode"] = "566";
	trans_info["TerminatingEntityCode"] = "057";
	trans_info["TerminatingPaymentMethodCode"] = "AC";
	logfmt(FLOG_MAX, "LOC 1 ==========================================================");
	char ptid[25];
	srand(time(NULL));
	long r = abs( rand()*10000);	
	sprintf( ptid, "117629%04lu",  r );
	trans_info["TransferCode"] = ptid; //"1176290012";
	trans_info["SenderLastname"] = "Ameye";
	trans_info["SenderOthernames"] = "Olu";
	trans_info["BeneficiaryLastname"] = "Ameye";
	trans_info["BeneficiaryOthernames"] = "Olu";

	logfmt(FLOG_MAX, "==========================================================");
	string result = interswitch_doTransfer(endpoint, "3MBA0001", trans_info, status);
	logfmt(FLOG_MAX, "Return: %s",result.c_str());
	logfmt(FLOG_MAX, "Status: %s",status);
/*
    CVars trans_info;

	logfmt(FLOG_MAX, "==========================================================");
	result = interswitch_transferFunds(endpoint, tid, mkey, pin, status, account, transCode, "039", 566, 100000, trans_info);
	logfmt(FLOG_MAX, "Return: %s",result.c_str());
	logfmt(FLOG_MAX, "Status: %s",status);
	logfmt(FLOG_MAX, "TransC: %s",transCode);
*/
	logfmt(FLOG_MAX, "==========================================================");
	result = interswitch_queryTransaction(endpoint, tid, "0", (const char *)transCode, status, transCode);
	logfmt(FLOG_MAX, "Return: %s",result.c_str());
	logfmt(FLOG_MAX, "Status: %s",status);
	logfmt(FLOG_MAX, "TransC: %s",transCode);
	logfmt(FLOG_MAX, "==========================================================");

	free(transCode);
	free(status);

  return ret;
}
/*****************************************************************************/

#ifdef TEST

int main(void) {
	interswitch_test();
	return 0;
}

#endif


/*
vi:ts=2
*/

































//</Response>

