#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/sco.h>
#include <arpa/inet.h>   
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>

#include "client.h"
#include "socket.h"

#define BILLION 1000000000

long get_file_size(FILE * file) {

   long size;
   fseek(file, 0, SEEK_END);
   size = ftell(file);
   fseek(file, 0, SEEK_SET);
   return size;

}


int send_file(int bt_socket, int len, bt_intfr_config * config){
   struct timespec start, stop;
   double accum;
   int i;
   int j = 0;
   
   if( clock_gettime( CLOCK_REALTIME, &start) == -1 ) {
      perror( "clock gettime" );
      exit( EXIT_FAILURE );
    }
   
   FILE *file;
   long size;
   int read_size, stat, packet_index;
   char send_buffer[len], read_buffer[256];
   packet_index = 1;

   file = fopen(config->filename, "r");
   printf("Obtaining file size.\n");   

   if(file == NULL) {
        printf("Error: File cannot be opened."); }

   size = get_file_size(file);
   printf("File size is: %li B\n",size);

   // Odeslat velikost souboru
   printf("Sending the file size.\n");
   write(bt_socket, (void *)&size, sizeof(long));

   // Odeslat velikost souboru jako bajtove pole
   printf("Sending the file size as byte array.\n");

   do { // Cteni dokud nedojde k chybam
      stat=read(bt_socket, &read_buffer , 255);
      printf("Byte array: %lu\n",sizeof(send_buffer));
   } while (stat < 0);

   printf("Data are received in the socket.\n");
   printf("Data in the socket: %lu\n",sizeof(send_buffer));

   while(!feof(file)) {
      // Cteni ze souboru do bufferu
      read_size = fread(send_buffer, 1, sizeof(send_buffer), file);

      // Poslani data pres socket 
      do{
        stat = write(bt_socket, send_buffer, read_size);  
      }while (stat < 0);

      printf("Sent packet number: %i\n",packet_index);
      printf("Sent packet size: %i B\n",read_size);     
      printf(" \n");
      printf(" \n");


      packet_index++;  

      // Uvolneni bufferu
      bzero(send_buffer, sizeof(send_buffer));
     }
      printf("Sent file size: %li B\n",size);

      if( clock_gettime( CLOCK_REALTIME, &stop) == -1 ) {
      perror( "clock gettime" );
      exit( EXIT_FAILURE );
     }

     accum = stop.tv_nsec - start.tv_nsec;
     accum /= BILLION;
     accum += stop.tv_sec - start.tv_sec;
     printf( "Sending - transmission time was: %lf s\n", accum );
     double rychlost;
     rychlost = size/accum;
     printf("Sending - transmission speed was: %lf B/s\n", rychlost);
}

void connect_l2cap_client(int s, bt_intfr_config * config)
{
	struct sockaddr_l2 addr = { 0 };
	int status, read_size,buffer = 0;
	char dest[18] = "00:1B:B1:60:E4:F0";

	strncpy(dest, config->bdaddr, 18);
	
	// nastaveni parametru spojeni
	addr.l2_family = AF_BLUETOOTH;
	addr.l2_psm = htobs(0x1001);
	str2ba( dest, &addr.l2_bdaddr );
		
	// pripojeni k serveru
	status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
		
	// posilani dat serveru
	if( status == 0 ) {

		printf("Connection accepted.\n");
	}

	if( status < 0 ) {
		perror("uh oh");
	}
}

void connect_sco_client(int s, bt_intfr_config * config)
{
	struct sockaddr_sco addr1 = { 0 };
	int status, read_size,buffer = 0;
	char dest[18] = "00:1B:B1:60:E4:F0";

	strncpy(dest, config->bdaddr, 18);
	
	// nastaveni parametru spojeni
	addr1.sco_family = AF_BLUETOOTH;
	str2ba( dest, &addr1.sco_bdaddr );

	// pripojeni k serveru
	status = connect(s, (struct sockaddr *)&addr1, sizeof(addr1));

	// posilani dat serveru
	if( status == 0 ) {

		printf("Connection accepted.\n");
	}

	if( status < 0 ) {
		perror("uh oh");
	}
}



void run_client(bt_intfr_config * config)
{
	int s;
	int mtu;

	printf("Running the client\n");

	printf("Protocol = %s\n", protocol_to_string(config->protocol));
	printf("BD_ADDR serveru = %s\n", config->bdaddr);
	if (config->protocol == L2CAP) {
		printf("Mode = %s\n", mode_to_string(config->mode));
	}	

	// prideleni socketu
	s = create_bound_socket(config);

	switch(config->protocol) {

		case L2CAP:
			mtu = 1021;
			connect_l2cap_client(s, config);
			break;

		case SCO:
			mtu = 64;
			connect_sco_client(s, config);
			break;
		default: 
			printf("%s: Unknown protocol.\n", __func__);
			break;
	}
	
	send_file(s, mtu, config);

	close(s);
}




