// C++ program to create calculator using
// switch statement
//#include <iostream>
//#include<string>
#include<unistd.h>
#include <pthread.h>
#include <limits.h>

#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
//#include <math.h>

#include "nd_sdk.h"
//using namespace std;
#define ND_GOAGENT

static const char *USAGE = " [-firup]\n \
							-f number of flowpaths\n \
							-i flowpath intervals (in seconds)\n \
							-r dbhost \n \
							-u user \n \
							-p password";
__thread ndBTHandle tlsBTHandle;
int num_flowpaths = 50;
int flowpath_intervals = 1;
char* dbhost = "localhost";
char* dbuser = "root";
char* dbpassword = "Cavisson@123";

 void* log(int level, const  char *func_name, const int line, const char *format, ...) {

 }
int parseArgs (int argc, char *argv[])
{
	int i = 0;
	int nflowpaths = 0;
	int interval = 0;
	char* db_host,db_user,db_password;
	while (++i < argc && *argv[i] == '-') {
		char *ptr = argv[i];
		while (*(++ptr)) {
			switch (*ptr) {
				case 'f':
					if (++i < argc) {
						nflowpaths = atoi(argv[i]);
					}

					if(nflowpaths <= 0) {
						//std::cerr << "-f option requires number of flowpaths" << endl;
						//cout << "usage: " << endl << USAGE << endl;
						return 0;
					}
					num_flowpaths = nflowpaths;
				break;

				case 'i':
					if (++i < argc) {
						interval = atoi(argv[i]);
					}

					if(interval <= 0) {
						//std::cerr << "-f option requires flowpaths interval in ms" << endl;
						//cout << "usage: " << endl << USAGE << endl;
						return 0;
					}
					flowpath_intervals = interval;
				break;

			case 'r':
					if (++i < argc) {
						db_host = argv[i];
					}

					if(!db_host) {
						//std::cerr << "-r option requires host" << endl;
						//cout << "usage: " << endl << USAGE << endl;
						return 0;
					}
					dbhost = db_host;
				break;

		case 'u':
					if (++i < argc) {
						db_user = argv[i];
					}

					if(!db_user) {
						//std::cerr << "-u option requires database user name" << endl;
						//cout << "usage: " << endl << USAGE << endl;
						return 0;
					}
					dbuser = db_user;
				break;

		case 'p':
					if (++i < argc) {
						db_password = argv[i];
					}

					if(!db_password) {
						//std::cerr << "-p option requires database password" << endl;
						//cout << "usage: " << endl << USAGE << endl;
						return 0;
					}
					dbpassword = db_password;
				break;

			case 'h':
				//cout << "usage: " << endl << USAGE << endl;
				return 0;
				break;

			}
		}
	}

	return 1;
}


void Displaysum(float num1, float num2, int http) {
	//cout << "bt "<< tlsBTHandle << " for thread " << pthread_self() <<endl;;
	nd_method_entry(tlsBTHandle,(char*)"pkg1.cls1.Displaysum",0);
	//cout << "sum " << num1 + num2<<endl;
	if(http && tlsBTHandle) {
		nd_ip_http_callout_begin("Displaysum",tlsBTHandle,"www.facebook.com",0);
		//fprintf(stderr, "icallout %p,%p\n", tlsBTHandle,icallout);
		char *cusheader = get_custom_nd_header(tlsBTHandle,"dbhost");
		//fprintf(stderr,"my custom header %s\n",cusheader);
		nd_ip_http_callout_end("Displaysum","dbhost",tlsBTHandle,200,0,0,NULL);
		 
	}
	nd_method_exit(tlsBTHandle,(char*)"pkg1.cls1.Displaysum",0,0,0,NULL);
}
void Displaydiff(float num1, float num2) {
	nd_method_entry(tlsBTHandle,(char*)"pkg1.cls1.Displaydiff",0);
	//cout << "diff "<<num1 - num2<<endl;
	nd_method_exit(tlsBTHandle,(char*)"pkg1.cls1.Displaydiff",0,0,0,NULL);
}
void Displayproduct(float num1, float num2) {
	nd_method_entry(tlsBTHandle,(char*)"pkg1.cls1.Displayproduct",0);
	//cout << "prod " << num1 * num2<<endl;
	nd_method_exit(tlsBTHandle,(char*)"pkg1.cls1.Displayproduct",0,0,0,NULL);
}
void Displaydiv(float num1, float num2) {
	nd_method_entry(tlsBTHandle,(char*)"pkg1.cls1.Displaydiv",0);
	//cout << "div " << num1 / num2<<endl;
	nd_method_exit(tlsBTHandle,(char*)"pkg1.cls1.Displaydiv",0,0,0,NULL);
}

void * threadFunc1(void * arg)
{
//return NULL;	
    //ndtlsBTHandle bthandle1 = NULL;
    int num_operations = 5;
	char *unique_bt_id_c = (char*)"2";
	float num1 = 100, num2 = 40;
	char *buf1 = "User-Agent$Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0|Accept$text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8|Accept-Language$en-US,en;q=0.5|Connection$keep-alive|Cookie$CavVI=001162044238532182018|Upgrade-Insecure-Requests$1|Sec-Fetch-Dest$document|Sec-Fetch-Mode$navigate|Sec-Fetch-User$?1|Accept-Encoding$gzip, deflate, br|Sec-Fetch-Site$none|Host$localhost:8086|";
	for(int i = 0;i < num_flowpaths; i++) {
		char btname[50];
		sprintf(btname,"threadFunc1_%d",i);
		ndBTHandle bthandle1 = nd_bt_begin(btname,NULL,NULL,NULL,NULL,NULL,0);

		tlsBTHandle = bthandle1;
		fprintf(stderr, "thread1 %s\n", btname);
		for(int j = 0; j < num_operations; j++) {
			switch (j) {
				case 0:
				case 4:
				case 8:
					Displaysum(num1, num2, 1);
					break;

				case 1:
				case 5:
				case 9:
					Displaydiff(num1, num2);
					break;

				case 2:
				case 6:
				case 10:
					Displayproduct(num1, num2);
					break;

				case 3:
				case 7:
				case 11:
					Displaydiv(num1,num2);
					break;
			}
		}
		sdk_httpReqRespWrapper(tlsBTHandle,buf1,"req",0);
		nd_bt_end(tlsBTHandle,0,0,0,0,NULL);
		num_operations++;
		num1++;
		num2++;
		if(num_operations > 10)
			num_operations = 5;
		sleep(flowpath_intervals);
	}

    return NULL;
}

void * threadFunc2(void * arg)
{
	//return NULL;
    //ndBTHandle bthandle2 = NULL;
    int num_operations = 5;
	char *unique_bt_id_c = (char*)"3";
	float num1 = 200, num2 = 140;
	char *buf1="Sec-Fetch-Dest$empty|Sec-Fetch-Mode$cors|Accept-Encoding$gzip, deflate, br|Cookie$influxdb-oss-session=q64-gqWZgebg1uYbkBG8lPg_570qbb47a9bmewYlyZc3BHXt5Xfgc3xdgI3X8141B4V-s1EjT9N27Xj5Qap5pw==; CavVI=001162044238532182018|Referer$http://localhost:8086/orgs/7382f9018a14daab/settings/secrets|Connection$keep-alive|Sec-Fetch-Site$same-origin|User-Agent$Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0|Accept$*/*|Accept-Language$en-US,en;q=0.5|Host$localhost:8086|";
	for(int i = 0;i < num_flowpaths; i++) {
		char btname[50];
		sprintf(btname,"threadFunc2_%d",i);
		fprintf(stderr, "thread2 %s\n", btname);
		ndBTHandle bthandle2 = nd_bt_begin(btname,NULL,NULL,NULL,NULL,NULL,0);
		tlsBTHandle = bthandle2;
		for(int j = 0; j < num_operations; j++) {
			switch (j) {
				case 0:
				case 4:
				case 8:
					Displaysum(num1, num2,0);
					break;

				case 1:
				case 5:
				case 9:
					Displaydiff(num1, num2);
					break;
				
				case 2:
				case 6:
				case 10:
					Displayproduct(num1, num2);
					break;

				case 3:
				case 7:
				case 11:
					Displaydiv(num1,num2);
					break;
			}
		}
		sdk_httpReqRespWrapper(tlsBTHandle,buf1,"req",0);
		nd_bt_end(tlsBTHandle,0,0,0,0,NULL);
		num_operations++;
		num1++;
		num2++;
		if(num_operations > 10)
			num_operations = 5;
		sleep(flowpath_intervals);
	}
    return NULL;
}

void * threadFunc3(void * arg)
{
	//return NULL;
    //ndBTHandle bthandle3 = NULL;
    int num_operations = 5;
	char *unique_bt_id_c = (char*)"4";
	float num1 = 300, num2 = 240;
	for(int i = 0;i < num_flowpaths; i++) {
		char btname[50];
		sprintf(btname,"threadFunc3_%d",i);
		fprintf(stderr, "thread3 %s\n", btname);
		ndBTHandle bthandle3 = nd_bt_begin(btname,NULL,NULL,NULL,NULL,NULL,0);
		tlsBTHandle = bthandle3;
		for(int j = 0; j < num_operations; j++) {
			switch (j) {
				case 0:
				case 4:
				case 8:
					Displaysum(num1, num2,0);
					break;
				
				case 1:
				case 5:
				case 9:
					Displaydiff(num1, num2);
					break;

				case 2:
				case 6:
				case 10:
					Displayproduct(num1, num2);
					break;

				case 3:
				case 7:
				case 11:
					Displaydiv(num1,num2);
					break;
			}
		}
		nd_bt_end(tlsBTHandle,0,0,0,0,NULL);
		num_operations++;
		num1++;
		num2++;
		if(num_operations > 10)
			num_operations = 5;
		sleep(flowpath_intervals);
	}
    return NULL;
}

void * threadFunc4(void * arg)
{
//	return NULL;
    //ndBTHandle bthandle4 = NULL;
//sleep(30);
    nd_init_sdk((char*)"calculator");
	//fprintf(stderr, "return5\n");
	pthread_t threadId1,threadId2,threadId3;

	pthread_attr_t tattr1,tattr2,tattr3;
	int ret;
	size_t size = 512*1024;;

	ret = pthread_attr_init(&tattr1);
	pthread_attr_setstacksize(&tattr1, size);

	ret = pthread_attr_init(&tattr2);
	pthread_attr_setstacksize(&tattr2, size);

	ret = pthread_attr_init(&tattr3);
	pthread_attr_setstacksize(&tattr3, size);

	

	int err = pthread_create(&threadId1, &tattr1, &threadFunc1, NULL);
	err = pthread_create(&threadId2, &tattr2, &threadFunc2, NULL);
	err = pthread_create(&threadId3, &tattr3, &threadFunc3, NULL);
	
	

	ndBTHandle bthandle = NULL;
	int num_operations = 5;
	char *unique_bt_id_c = (char*)"1";
	float num1 = 50, num2 = 20;
	for(int i = 0;i < num_flowpaths; i++) {
		char btname[50];
		sprintf(btname,"arthmetic_operation_%d",i);
		fprintf(stderr, "thread4 %s\n", btname);
		bthandle = nd_bt_begin(btname,NULL,NULL,NULL,NULL,NULL,0);
		tlsBTHandle = bthandle;
		for(int j = 0; j < num_operations; j++) {
			switch (j) {
				case 0:
				case 4:
				case 8:
					Displaysum(num1, num2,0);
					break;

				case 1:
				case 5:
				case 9:
					Displaydiff(num1, num2);
					break;

				case 2:
				case 6:
				case 10:
					Displayproduct(num1, num2);
					break;

				case 3:
				case 7:
				case 11:
					Displaydiv(num1,num2);
					break;
			}
		}
		nd_bt_end(tlsBTHandle,0,0,0,0,NULL);
		num_operations++;
		num1++;
		num2++;
		if(num_operations > 10)
			num_operations = 5;
		sleep(flowpath_intervals);
	}

	pthread_join(threadId1, NULL);
	pthread_join(threadId2, NULL);
	pthread_join(threadId3, NULL);

    return NULL;
}

// Main program
int main(int argc, char *argv[])
{	
	if(!parseArgs(argc,argv))
		return 0;
	pthread_attr_t tattr4;
	pthread_t threadId4;
size_t size = 512*1024;;
	int ret = pthread_attr_init(&tattr4);
	pthread_attr_setstacksize(&tattr4, size);

	int err = pthread_create(&threadId4, &tattr4, &threadFunc4, NULL);

	
	pthread_join(threadId4, NULL);

	return 0;
}

