#include <stdio.h>
#include <stdlib.h>
#include <curl/curl.h>
#include <curl/easy.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#define S1READY 0x01
#define S2READY 0X02

void usage(void){
	printf("Error incorrect usage!\n");
	printf("Usage:\n");
	printf("\tlsync <http://website.com>\n");
}


int Select_Wait(unsigned int port){
	fd_set fds;
	struct timeval timeout;
	int rc, result;
	timeout.tv_sec = 3;
	timeout.tv_usec = 0;

	FD_ZERO(&fds);
	FD_SET(port, &fds);
	rc = select(sizeof(fds)*8, &fds, NULL, NULL, &timeout);
	if (rc==-1) {
		perror("select failed");
		return -1;
	}

   result = 0;
   if (rc > 0)
   {
      if (FD_ISSET(port, &fds)) result |= S1READY;
      //if (FD_ISSET(s2, &fds)) result |= S2READY;
   }

   return result;


	//select(int nfds, fd_set *readfds, NULL, NULL, const struct timeval *timeout);


}



int main(int argc, char **argv){
	CURL *Curl_Easy_Handle;
	CURLcode Ret_Value;
	size_t file_bytes;
	size_t recv_bytes;
	double Transfer_Size;
	double Transfer_Time;
	unsigned int Counter1;
	char *Version_String;
	char *Error_Buffer;
	char *URL_Buffer;
	FILE *File_Buffer;
	int file_des;
	size_t error_value;
	char buf[10001];
	long Last_Sock;

	if(argc != 2){
		usage();
		return 1;
	}

	URL_Buffer = malloc(strlen(argv[1])*sizeof(char)+1 );

	memset(URL_Buffer, '\0', strlen(argv[1])+1);

	memcpy(URL_Buffer, argv[1], strlen(argv[1]));
	

	printf("%s\n", argv[1]);
	printf("%s\n", URL_Buffer);
	//printf("size: %u\n", strlen( argv[1] ) );

//return 0;
	//long Error_Num_Var;

	Ret_Value = curl_global_init(CURL_GLOBAL_ALL);
	if(Ret_Value != 0){
		printf("curl_global_init failed with return value: %u\n", Ret_Value);
		return 1;
	}

	Curl_Easy_Handle = curl_easy_init( );
	if(Curl_Easy_Handle == NULL){
		printf("curl_easy_init failed with NULL return value\n");
		return 1;
	}
//curl_easy_cleanup(Curl_Easy_Handle);
#ifdef VERBOSE
	Ret_Value =  curl_easy_setopt(Curl_Easy_Handle, CURLOPT_VERBOSE, 1); 
	if(Ret_Value != CURLE_OK){
		printf("curl_easy_setopt failed with return value: %u\n", Ret_Value);
		return 1;
	}
#endif

	Ret_Value =  curl_easy_setopt(Curl_Easy_Handle, CURLOPT_CONNECT_ONLY, 1);
	if(Ret_Value != CURLE_OK){
		printf("curl_easy_setopt failed with return value: %u\n", Ret_Value);
		if(Ret_Value == CURLE_FAILED_INIT){
			printf("\tCURLE_FAILED_INIT: try upgrading your curl version\n");
		}
		return 1;
	}

	Ret_Value = curl_easy_setopt(Curl_Easy_Handle, CURLOPT_ERRORBUFFER, Error_Buffer);
	if(Ret_Value != CURLE_OK){
		printf("curl_easy_setopt failed with return value: %u\n", Ret_Value);
		return 1;
	}

	Version_String = curl_version( );
	printf("Curl Version: %s\n", Version_String);

	Ret_Value = curl_easy_setopt(Curl_Easy_Handle, CURLOPT_URL, URL_Buffer);
	if(Ret_Value != CURLE_OK){
		printf("curl_easy_setopt failed with return value: %u\n", Ret_Value);
		return 1;
	}

	Ret_Value = curl_easy_setopt(Curl_Easy_Handle, CURLOPT_HTTPGET, 1);
	if(Ret_Value != CURLE_OK){
		printf("curl_easy_setopt failed with return value: %u\n", Ret_Value);
		return 1;
	}




	//loop
	//{

	//setup the url
//	CURLOPT_URL



//	file_des = open("./test_file" , O_CREAT | O_TRUNC | O_RDWR, 0644);
//	close(file_des);error_value
//	file_des = open("./test_file" , O_RDWR);

	file_bytes = 40000000;


	//if( ( file_des = fopen( "./test_file", "w" ) ) == NULL ) {
	//	fprintf( stderr, "Error writing to filesystem\n");
	//	exit ( 1 );
	//}

//Ret_Value = lseek(file_des, 0, SEEK_SET);
//printf("result %u\n", Ret_Value);
//    if (Ret_Value == -1) {
//        close(file_des);
//        perror("Error calling lseek() to 'stretch' the file");
//        exit(EXIT_FAILURE);
//    }
        
//    Ret_Value = write(file_des, "", 1);
//    if (Ret_Value != 1) {error_value
//        close(file_des);  
//        perror("Error writing last byte of the file");
//        exit(EXIT_FAILURE);
//    }


//        File_Buffer=mmap(0, file_bytes, PROT_READ|PROT_WRITE, MAP_SHARED, file_des, 0);
//        if (File_Buffer == MAP_FAILED) {
//                close(file_des);
//                perror("Error mmapping the file");
//                exit(EXIT_FAILURE);
//        }

	if( ( File_Buffer = fopen("./test_file", "w") ) == NULL){
		fprintf( stderr, "Error opening file\n" );
		return 1;
	}
printf("here 1\n");

	//CURLINFO_LASTSOCKET
//	Ret_Value = curl_easy_getinfo(Curl_Easy_Handle, CURLINFO_LASTSOCKET, &Last_Sock);
//        if(Ret_Value != CURLE_OK){
//                printf("curl_easy_getinfo failed with error code: %u\n", Ret_Value);
//                return 1;
//        }
printf("here 2: socket %lu\n", Last_Sock);

        Ret_Value = curl_easy_perform(Curl_Easy_Handle);
        if(Ret_Value != CURLE_OK){
                printf("curl_easy_perform failed with error: %s\n", Error_Buffer);  
                return 1;
        }

        Ret_Value = curl_easy_getinfo(Curl_Easy_Handle, CURLINFO_LASTSOCKET, &Last_Sock);
        if(Ret_Value != CURLE_OK){
                printf("curl_easy_getinfo failed with error code: %u\n", Ret_Value);
                return 1;
        }
printf("here 2: socket %lu\n", Last_Sock);


//	curl_easy_reset(Curl_Easy_Handle);


//	Ret_Value = curl_easy_setopt(Curl_Easy_Handle, CURLOPT_WRITEDATA, File_Buffer);
//	if(Ret_Value != CURLE_OK){
//		printf("curl_easy_setopt failed with return value: %u\n", Ret_Value);
//		return 1;
//	}

	Ret_Value = CURLE_AGAIN;
	Counter1 = 0;
	recv_bytes = 0;

	while(Ret_Value == CURLE_AGAIN){

		Ret_Value = Select_Wait(Last_Sock);
		if(Ret_Value == -1){
			return(1);
		}	
		Ret_Value = curl_easy_recv(Curl_Easy_Handle, &buf , 10000 , &recv_bytes); 
		if(Ret_Value != CURLE_OK && Ret_Value != CURLE_AGAIN){
			printf("recv_bytes %lu\n", recv_bytes);
			printf("Ret_Value: %u\n", Ret_Value);
printf("curl_easy_recv failed with error: %s\n",curl_easy_strerror(Ret_Value) );
			//printf("curl_easy_recv failed with error: %s\n", Error_Buffer);

			return 1;
		}
		if(Counter1 == 25){
			printf("Failed to establish socket connection in 25 trys\n");
			return 1;
		}
		Counter1++;
		//sleep(1);
	}

printf("here 3\n");

//	Ret_Value = curl_easy_perform(Curl_Easy_Handle);
//	if(Ret_Value != CURLE_OK){
//		printf("curl_easy_perform failed with error: %s\n", Error_Buffer);
//		return 1;
//	}


//	Ret_Value = msync(File_Buffer, file_bytes, MS_SYNC);
//	if(Ret_Value != 0){
//		fprintf( stderr, "Error writing to filesystem: msync %u\n", Ret_Value );
//		if (munmap(File_Buffer, file_bytes) == -1) {
//			perror("Error un-mmapping the file");
//	      	}
//		close(file_des);
//		exit( 1 );
//	}

	//msync time not included
	Ret_Value = curl_easy_getinfo(Curl_Easy_Handle, CURLINFO_TOTAL_TIME, &Transfer_Time);
	if(Ret_Value != CURLE_OK){  // 0
		printf("curl_easy_getinfo failed with error code: %u\n", Ret_Value);
		return 1;
	}

	Ret_Value = curl_easy_getinfo(Curl_Easy_Handle, CURLINFO_SIZE_DOWNLOAD, &Transfer_Size);
	if(Ret_Value != CURLE_OK){
		printf("curl_easy_getinfo failed with error code: %u\n", Ret_Value);
		return 1;
	}

	Transfer_Size = Transfer_Size/1024/1024;
	printf("Transfer complete: %.02lfMB at %.02lfMB/s\n", Transfer_Size, Transfer_Size/Transfer_Time);
 

	//}


//CURLINFO_SPEED_DOWNLOAD
//CURLINFO_OS_ERRNO

	(void)curl_easy_cleanup(Curl_Easy_Handle);

//        if (munmap(File_Buffer, file_bytes) == -1) {
//                perror("Error un-mmapping the file");
//        }
//        close(file_des);

	fclose(File_Buffer);
	return 0;
}
