#include <zephyr.h>
#include <net/socket.h>
#include <misc/printk.h>
#include <zephyr/types.h>
#include <math.h>
#include <soc.h>
#include <gpio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>     /* atof */

#include <autoconf.h>



#define AT_MAX_CMD_LEN 4096
#define INVALID_DESCRIPTOR -1

#define UART_RX_BUF_SIZE 4096 

#define CMD_STATE 0
#define RESPOND_STATE 1

#define UART_BUF_SIZE           1024
#define RECV_BUF_SIZE 1024

char recv_buf[RECV_BUF_SIZE + 1];

const char *at_commands[] = {
	"AT+CGMM", "AT+CGDCONT?", "AT%XCBAND=?", "AT+CGSN=1",
	"AT+CESQ",
	// Add more here if needed 
};

/****************************************************************************************************
*name: 
*to do:  SPLIT the String with pattern()
*return: 
****************************************************************************************************/
void stringsplit(char *str)
{
	//char str[] = "strtok needs to be called several times to split a string";
	int init_size = strlen(str);
	char delim[] = " ";

	char *ptr = strtok(str, delim);

	while(ptr != NULL)
	{
		printf("'%s'\n", ptr);
		ptr = strtok(NULL, delim);
	}

	/* This loop will show that there are zeroes in the str after tokenizing */
	for (int i = 0; i < init_size; i++)
	{
		printf("%d ", str[i]); /* Convert the character to integer, in this case
							   the character's ASCII equivalent */
	}
	printf("\n");

	return 0;
}
/****************************************************************************************************
*name: 
*to do:  SPLIT the String with pattern()
*return: 
****************************************************************************************************/
void split_string_ltepos(char *str, char splitStrings[10][10])
{
   // char str[100];
     //can store 10 words of 10 characters
    int i,j,cnt;
    j=0; cnt=0;
    for(i=0;i<=(strlen(str));i++)
    {
        // if space or NULL found, assign NULL into splitStrings[cnt]
        if(str[i]=='"'||str[i]=='\0')
        {
            splitStrings[cnt][j]='\0';
            cnt++;  //for next word
            j=0;    //for next word, init index to 0
        }
        else
        {
            splitStrings[cnt][j]=str[i];
            j++;
        }
    }
    printk("\nOriginal String is: %s",str);
    /*
    printk("\nStrings (words) after split by space:\n");
    for(i=0;i < cnt;i++)
        printk("%s\n",splitStrings[i]);
    */
   // return splitStrings;
}

/****************************************************************************************************
*name:  blocking_recv()
*to do: receive data 
*return: 
****************************************************************************************************/
int blocking_recv(int fd, u8_t *buf, u32_t size, u32_t flags)
{
	int err;

	do {
		err = recv(fd, buf, size, flags);
	} while (err < 0 && errno == EAGAIN);

	return err;
}
/****************************************************************************************************
*name:  blocking_send
*todo:  send data 
*return: 
****************************************************************************************************/

int blocking_send(int fd, u8_t *buf, u32_t size, u32_t flags)
{
	int err;

	do {
		err = send(fd, buf, size, flags);
	} while (err < 0 && errno == EAGAIN);

	return err;
}

/****************************************************************************************************
*name:  blocking_connect
*todo:  connect block()
*return: 
****************************************************************************************************/

int blocking_connect(int fd, struct sockaddr *local_addr, socklen_t len)
{
	int err;

	do {
		err = connect(fd, local_addr, len);
	} while (err < 0 && errno == EAGAIN);

	return err;
}

/****************************************************************************************************
*name:  nRF_LTE_check
*todo:  check nRF LTE connect
*return: return at_commands[]
****************************************************************************************************/
int nRF_LTE_check(void)
{
        int err;
        const char *ATREG="AT+CEREG?"; 
	int at_socket_fd = socket(AF_LTE, 0, NPROTO_AT);
        //printk("LTE socket is: %d \n",at_socket_fd); 

	printk("Checking LTE_M signal.............\n\r");

	if (at_socket_fd < 0) {
		err = 1; 
	}
        else {
            err = 0;
            int bytes_written2 = send(at_socket_fd, ATREG, strlen(ATREG), 0);
            k_sleep(5000);
            if (bytes_written2 > 0) {
		int r_bytes2 = blocking_recv(at_socket_fd, recv_buf,sizeof(recv_buf), MSG_DONTWAIT);
		if (r_bytes2 > 0) {
				printk("%s", recv_buf);
                                char splitStringstac[10][10]; 
                                split_string_ltepos(recv_buf,splitStringstac); 
                                if (splitStringstac[0] == 0) 
                                  {
                                    err = 1; 
                                    printk("Cant find LTE_M signal \n");
                                  }
                                 else {
                                    printk("Found the LTE_M signal \n");
                                    err =0;
                                 }

	                       }
                          }
          }
	printk("Closing socket\n\r");
	//(void)close(at_socket_fd);
        return err; 
}
/****************************************************************************************************
*name:  app_socket_start
*todo:  send the const char *at_commands[]
*return: return at_commands[]
****************************************************************************************************/
void app_socket_start(void)
{
	int at_socket_fd = socket(AF_LTE, 0, NPROTO_AT);
        printk("LTE socket is: %d \n",at_socket_fd); 

	printk("Starting simple AT socket application\n\r");

	if (at_socket_fd < 0) {
		printk("Socket err: %d, errno: %d\r\n", at_socket_fd, errno);
	}
	for (int i = 0; i < ARRAY_SIZE(at_commands); i++) {
		int bytes_written = send(at_socket_fd, at_commands[i],
					 strlen(at_commands[i]), 0);
		if (bytes_written > 0) {
			int r_bytes =
				blocking_recv(at_socket_fd, recv_buf,
					      sizeof(recv_buf), MSG_DONTWAIT);
			if (r_bytes > 0) {
				printk("%s", recv_buf);
			}
		}
	}
	printk("Closing socket\n\r");
	(void)close(at_socket_fd);
}

/****************************************************************************************************
*name:  LTE_socket_com
*todo:  send AT command
* use:   LTE_socket_com("AT"); 
         LTE_socket_com("AT+CPIN?"); 
*return: 
****************************************************************************************************/
void LTE_socket_com(const char *lte_at_cmd )
{
	int at_socket_fd = socket(AF_LTE, 0, NPROTO_AT);
        printk("LTE socket is: %d \n",at_socket_fd); 

	//printk("Starting simple AT socket application\n\r");
        printk("AT cmd: %s \n\r",lte_at_cmd);

	if (at_socket_fd < 0) {
		printk("Socket err: %d, errno: %d\r\n", at_socket_fd, errno);
	}
	//for (int i = 0; i < ARRAY_SIZE(lte_at_cmd); i++) {
        
	int bytes_written = send(at_socket_fd, lte_at_cmd, strlen(lte_at_cmd), 0);
	if (bytes_written > 0) {
			int r_bytes =
				blocking_recv(at_socket_fd, recv_buf,
					      sizeof(recv_buf), MSG_DONTWAIT);
			if (r_bytes > 0) {
				printk("%s", recv_buf);
			}
		
	}
	//printk("Closing socket\n\r");
	(void)close(at_socket_fd);
}


/****************************************************************************************************
*name:  LTE_AT_position
*todo:  find GMS position
*return: MCCMNC / LAC / CID
  * MCC — a Mobile Country Code
  * MNC - a Mobile Network Code
  * LAC - Location Area Code
  * CID : CellID 
****************************************************************************************************/
void LTE_AT_position(char *mccmnc,char *lac, char *cid )
 {
	const char *ATCOPS="AT+COPS?"; 
        const char *ATREG2="AT+CEREG=2"; 
        const char *ATREG="AT+CEREG?"; 
        
        int at_socket_fd = socket(AF_LTE, 0, NPROTO_AT);
       // printk("LTE socket is: %d \n",at_socket_fd); 
	
	if (at_socket_fd < 0) {
		printk("Socket err: %d, errno: %d\r\n", at_socket_fd, errno);
	}
	/*
        * find MNC and MCC
        */
        int bytes_written0 = send(at_socket_fd, ATCOPS, strlen(ATCOPS), 0);
	if (bytes_written0 > 0) {
			int r_bytes =
				blocking_recv(at_socket_fd, recv_buf,
					      sizeof(recv_buf), MSG_DONTWAIT);
			if (r_bytes > 0) {
				//printk("%s", recv_buf);
                                char splitStringsmcc[10][10]; 
                                 split_string_ltepos(recv_buf,splitStringsmcc);
                                 memcpy(mccmnc,splitStringsmcc[1],sizeof(splitStringsmcc[1]));
                                
                                 // printk("MCC&MNC: %s\n",mccmnc);
			              }
		
	}
        int bytes_written1 = send(at_socket_fd, ATREG2, strlen(ATREG2), 0);
        if (bytes_written1 > 0) {
		blocking_recv(at_socket_fd, recv_buf,sizeof(recv_buf), MSG_DONTWAIT);
			
	}
        /*************************************
        * find LAC and CID 
        ***************************************/
        int bytes_written2 = send(at_socket_fd, ATREG, strlen(ATREG), 0);
        if (bytes_written2 > 0) {
		int r_bytes2 = blocking_recv(at_socket_fd, recv_buf,sizeof(recv_buf), MSG_DONTWAIT);
		if (r_bytes2 > 0) {
				printk("%s", recv_buf);
                                char splitStringstac[10][10]; 
                                split_string_ltepos(recv_buf,splitStringstac); 
                                memcpy(lac,splitStringstac[1],sizeof(splitStringstac[1]));
                                memcpy(cid,splitStringstac[3],sizeof(splitStringstac[3]));

	                       }
                          }
	//printk("Closing socket\n\r");
	(void)close(at_socket_fd);
}

/******************************************"**************************************/
#define MAXLINE 4096
#define HTTP_HOST "142.93.37.192"
#define HTTP_PORT 7000
#define HTTP_PATH "/"
#define TEST_STRING  "Hello from nRF9160 DK"

#define POST_TEMPLATE "POST %s? HTTP/1.1\r\n"\
		"Host: %s\r\n"\
		"Connection: keep-alive\r\n"\
	        "Content-type: application/x-www-form-urlencoded\r\n"\
		"Content-length: %d\r\n\r\n"\
		"%s"
/****************************************************************************************************
*name:  app_http_get:
*todo:    HTTP GET from webserver: http://142.93.37.192
*return: return from HTTP GET
*use:     app_http_get(); 
****************************************************************************************************/
void app_http_get(void)
{
	struct sockaddr_in local_addr;
	struct addrinfo *res;

	local_addr.sin_family = AF_INET;
	local_addr.sin_port = htons(0);
	local_addr.sin_addr.s_addr = 0;

	printk("HTTP GET  http://142.93.37.192  example\n\r");

	int err = getaddrinfo(HTTP_HOST, NULL, NULL, &res);

	printk("getaddrinfo err: %d\n\r", err);
	((struct sockaddr_in *)res->ai_addr)->sin_port = htons(HTTP_PORT);

	char send_buf[] =
		"GET / HTTP/1.1\r\nHost: http://142.93.37.192:80\r\nConnection: close\r\n\r\n";
	int send_data_len = strlen(send_buf);

	int client_fd = socket(AF_INET, SOCK_STREAM, 0);

	printk("client_fd: %d\n\r", client_fd);
	err = bind(client_fd, (struct sockaddr *)&local_addr,
		   sizeof(local_addr));
	printk("bind err: %d\n\r", err);
	err = blocking_connect(client_fd, (struct sockaddr *)res->ai_addr,
			       sizeof(struct sockaddr_in));
	printk("connect err: %d\n\r", err);

	int num_bytes = send(client_fd, send_buf, send_data_len, 0);

	printk("send err: %d\n\r", num_bytes);

	
	num_bytes = blocking_recv(client_fd, recv_buf, RECV_BUF_SIZE, 0);
		
	printk("%s", recv_buf);
	
	//printk("\n\rFinished. Closing socket");
	//err = close(client_fd);
}


/****************************************************************************************************
*name:  app_http_post_bk
*todo:  HTTP POST PostString[] to webserver http://142.93.37.192
*return: 
* use:
****************************************************************************************************/

void app_http_post(char *PostString)
{  
	//int err; 
        struct sockaddr_in local_addr;
	struct addrinfo *res;

	local_addr.sin_family = AF_INET;
	local_addr.sin_port = htons(0);
	local_addr.sin_addr.s_addr = 0;

	    
	int err = getaddrinfo(HTTP_HOST, NULL, NULL, &res);

	printk("getaddrinfo err: %d\n\r", err);
	((struct sockaddr_in *)res->ai_addr)->sin_port = htons(HTTP_PORT);
        
        char send_buf[MAXLINE + 1];
	
	int send_data_len_post = snprintf(send_buf,
				         500, /*total length should not exceed MTU size*/
				         POST_TEMPLATE, HTTP_PATH,
				         HTTP_HOST, strlen(PostString),
				         PostString);

	printk("send err: %d\n\r", send_data_len_post);


	int client_fd = socket(AF_INET, SOCK_STREAM, 0);

	printk("client_fd: %d\n\r", client_fd);
	err = bind(client_fd, (struct sockaddr *)&local_addr,
		   sizeof(local_addr));
	printk("bind err: %d\n\r", err);
        // connect
	err = blocking_connect(client_fd, (struct sockaddr *)res->ai_addr,
			       sizeof(struct sockaddr_in));
	printk("connect err: %d\n\r", err);
       //send
        blocking_send(client_fd, send_buf, send_data_len_post, 0);
        k_sleep(1000);
       
	printk("\n\r HTTP POST Finished. \n\r");
	close(client_fd);

       
}



/****************************************************************************************************
*name:  nRF_LTE_check
*todo:  check nRF LTE connect
*return: return at_commands[]
****************************************************************************************************/
int nRF_LTE_CLOSE(void)
{
        int err;
        int at_socket_fd = socket(AF_LTE, 0, NPROTO_AT);
        
        err = close(at_socket_fd);
        printk("Close the socket LTE_M \n");
	return err; 
}