//
// anyRemote
// a wi-fi or bluetooth remote for your PC.
//
// Copyright (C) 2006-2016 Mikhail Fedotov <anyremote@mail.ru>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//

#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <termios.h>
#include <unistd.h>

#include "lib_wrapper.h"

#include "btio.h"
#include "common.h"
#include "parse.h"
#include "utils.h"
#include "conf.h"

extern char tmp[MAXMAXLEN];
extern boolean_t stillRun;

static int port_fd       = -1;

/*int bt_read(int portfd, char* buf, int len)
{
    return read(portfd, buf, len);
}*/

static int bt_read_tmo(int fd, char* buf, int len, int timeout)
{
    int ok;
    fd_set rdfds;
    struct timeval tv;
    
    if (fd < 0) {  // connection was somehow closed or lost
        return EOF;
    }

    FD_ZERO(&rdfds);
    FD_SET(fd, &rdfds);

    /* block until something to read or timeout occurs.  select() is damn cool */
    if (timeout < 0) {
        ok = select(fd + 1, &rdfds, NULL, NULL, NULL);
    } else {
        tv.tv_sec = timeout / 1000000;
        tv.tv_usec = (timeout % 1000000);
        ok = select(fd + 1, &rdfds, NULL, NULL, &tv);
    }

    if (ok > 0) {
        ok = read(fd, buf, len);
        if (ok == 0) {
            logger(L_DBG, "EOF during read()");
            return EOF;
        }

        /////////////////////////////////////
        //if(ok > 0){
        //	char buf2[1024];
        //	strncpy(buf2,buf,ok);
        //	sprintf(tmp, "READ: %s", buf2);
        //	logger(L_DBG, tmp);
        //}
        //////////////////////////////////////
        return ok;

    } else {

        return 0;

        //if (ok < 0) {
        //    return -1;
        //} else {
        //    errno = ETIMEDOUT;
        //    return 0;
        //}
    }
}

int  bt_readchar(int fd, char* c, int timeout)
{
    char buf[1];
    *c = 0;

    int rv =  bt_read_tmo(fd, buf, 1, timeout);
    /*if (rv != 0) {
    	sprintf(tmp, "bt_read_tmo returns: %d", rv);
    	logger(L_DBG, tmp);
    }*/

    if (rv == 1) {
        *c =  buf[0];
        return 1;
    }
    if (rv == 0) {
        return EOF - 1;
    }

    //  else - EOF
    close(fd);
    
    return EOF;
}

// max should be >= 100
int bt_put_command(int fd,
                   const char* command,
                   char* answer,
                   int   max,
                   int   timeout,
                   char* expect)
{
    int count=0;
    int readcount;
    char tmp2[100];
    int timeoutcounter=0;
    int found=0;

    if (fd < 0) {
        return 0;
    }

    logger(L_DBG,command);
    if (expect != NULL) {
        logger(L_DBG,expect);
    }

    // send command
    if (command && command[0]) {
        #ifdef __cplusplus
        ssize_t dummy = 
        #endif
            write(fd,command,strlen(command));
	
        tcdrain(fd);
    }

    if (max == 0) {
        return 0;
    }

    answer[0]=0;
    do {
        // try to read some bytes.
        usleep(100000);
        //write(1,".",1);
        timeoutcounter++;

        // read data
        readcount=read(fd,tmp2,sizeof(tmp2)-1);
        if (readcount<0) {
            readcount=0;
        }
        tmp2[readcount]=0;

        // add read bytes to the output buffer
        if (readcount) {
            strcat(answer,tmp2);
            count+=readcount;

            // if we have more time to read, check if we got already the expected string
            if ((timeoutcounter<timeout) && (found==0)) {

                // check if it's the expected answer
                if ((strstr(answer,"OK\r") || strstr(answer,"ERR")) && expect == NULL) {
                    found=1;
                }

                if (expect && expect[0]) {
                    if (strstr(answer,expect)) {
                        sprintf(tmp, "Got expected %s (iteration %d)", answer, timeoutcounter);
                        logger(L_DBG, tmp);
                        found=1;
                    }
                }

                // if found then set timoutcounter to read only 0.1s after that and not more
                if (found) {
                    //timeoutcounter=timeout-1;
                    break;
                }
            }
        }
    }
    // repeat until timout
    while (timeoutcounter<timeout && count < max);

    if (getLog()) {
        char *a2 = answer;

        while (a2[0] == '\r' || a2[0] == '\n')  {
            a2++;
        }
        logger(L_DBG,a2);
    }

    return count;
}

//
// Support for local server mode sockets
//
static int unix_open_port(char* port)
{
    sprintf(tmp, "unix_open_port >%s<", port);
    logger(L_INF, tmp);

    struct sockaddr_un serveraddr;

    port_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
    if (port_fd < 0) {
        sprintf(tmp, "can not open UNIX %s", port);
        logger(L_ERR, tmp);
        printf("ERROR: can not open UNIX %s\n", port);
        port_fd = -1;
        return -1;
    }
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sun_family = AF_UNIX;
    strncpy(serveraddr.sun_path, port, sizeof serveraddr.sun_path - 1);

    int ret = connect(port_fd, (struct sockaddr *)&serveraddr, SUN_LEN(&serveraddr));
    if (ret < 0) {
        sprintf(tmp, "can not open UNIX socket %s", port);
        logger(L_ERR, tmp);
        printf("ERROR: can not open UNIX socket %s\n", port);
        port_fd = -1;
        return -1;
    }

    return 0;
}

int uxsFD(ConnectInfo* connInfo)
{
    return port_fd;
}

int uxsOpen(ConnectInfo* connInfo)
{
    DEBUG2("[DS]: Unix socket client mode. Use port %s", connInfo->portStr->str);
    if (unix_open_port(connInfo->portStr->str) < 0) {
    	printf("ERROR: open inputlircd socket\n");
    	return EXIT_NOK;
    }
    connInfo->state = PEER_CONNECTED;
    return EXIT_OK;
}

void uxsClose(ConnectInfo* connInfo, int final)
{
    int retval = 0;
    //printf("INFO: Close port\n");

    if (port_fd < 0) { /* already closed */
        //printf("INFO: Already closed ?\n");
        return;
    }

    retval = close(port_fd);
    port_fd = -1;
    connInfo->state = PEER_DISCONNECTED;
    
    if (retval < 0) {
        logger(L_ERR,"[DS]: Error on closing AF_UNIX socket\n");
    }
}

void uxsReset(ConnectInfo* connInfo)
{
    uxsClose(connInfo, 0);
}

/*
int unix_read_port(char* buf, int l)
{
	int ret = 0;
	int bytesReceived = 0;
	printf("SOCKET: read fd %d\n", portfd);

	while (bytesReceived < l-1)
	{
		int rc = recv(port_fd, & buf[bytesReceived], l - bytesReceived, 0);
		printf("unix_read_port %d\n",rc);
		if (rc < 0) {
	   		//logger(L_ERR,"recv() failed");
			ret = EOF-1;
	   		break;
		} else if (rc == 0) {
	   		//logger(L_INF,"Read 0 bytes");
			ret = EOF;
	   		break;
		}

		bytesReceived += rc;
		ret = bytesReceived;
	}
	buf[bytesReceived] = '\0';

	return ret;
}
*/

