/*
 * btrcu plugin for VDR
 *
 * btrcu.c - BtRCU control class
 *
 * Copyright (C) 2004 Roland Praml <pram @ gmx . de>
 *
 * This code is distributed under the terms and conditions of the
 * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
 */

#include <linux/input.h>
#include <string.h>
#include <errno.h>

#include "btrcu.h"

#include <vdr/remote.h>
#include <vdr/tools.h>
#include "pduconv.h"

enum {
	OK=1,
	ERROR,
	CLIP,
	CLCK,
	CKEV,
	CREG,
	SMS,
	CMTI,
	UNKNOWN,
	EMPTY,
	CONNLOST,
};

cBtRCU * BtRCU;


cBtRCU::cBtRCU(const char * dev, const char * script) : cRemote("BT") {
	strcpy(rfdevice, dev);
	strcpy(ctrlScript, script);
	printf("[BtRCU] config %s %s\n",rfdevice, ctrlScript);
	fd=-1;
	pdulen=0;
	active=0;
	bufpos=0;
	Start();
}

cBtRCU::~cBtRCU()
{
	active=0;
	Cancel();
}
bool cBtRCU::ctrl(const char * action, const int param) {
    char tmp[32];
    printf("converting");
    sprintf(tmp,"%d",param);
    return ctrl(action,tmp);
}    


bool cBtRCU::ctrl(const char * action, const char * param) {
    char *tmp=0;
    asprintf(&tmp,"\"%s\" \"%s\" \"%s\"",ctrlScript,action,param);
    printf("[BtRCU] executing %s",tmp);
    bool res= (system(tmp)==0);
    printf("[BtRCU] action %s, param %s, res %d\n",action,param,res);
    return res;
}

#define PACK(i) ((i>'9')?(i-'A'+10):(i-'0'))
int cBtRCU::accept() {
	if(buf[0]=='\0'){
		return EMPTY;
	}

	if (pdulen) {
	    //DPRINT("pdu: %s\n", buf);
	    int i = 0; 
	    while ((buf[2*i] >= '0') &&
		   (buf[2*i] <= '9') ||
		   (buf[2*i] >= 'A') &&
		   (buf[2*i] <= 'F'))
	    {
		buf[i]= (unsigned char)(PACK(buf[2*i])*16+PACK(buf[2*i+1]));
		i++;
	    }
	    pdu_to_ascii((unsigned char *)buf+27,i-27, smstext);
	    printf("[BtRCU] SMS: %s\n", smstext);
	    pdulen=0;
	    return SMS;
	}

	printf("[BtRCU] <-- %s\n",buf);
	if(buf[0]=='+'){
		// decode CLIP-number
		if(strncasecmp(buf,"+CLIP: ",7)==0){
			int res;
			res=sscanf(buf,"+CLIP: \"%63[^\"]\",%d",
				   clipnr,&cliptype);
			if(res==2){
				return CLIP;
			}
			res=sscanf(buf,"+CLIP: %63[^,],%d",
				   clipnr,&cliptype);
			if(res==2){
				return CLIP;
			}
			return ERROR;

		}
		// decode Keylock
		if(strncasecmp(buf,"+CLCK: ",7)==0){
			int res;
			res=sscanf(buf,"+CLCK: %d",
				   &keylock);
			if(res==1){
				return CLCK;
			}
			return ERROR;
		}
		// decode network registration
		if(strncasecmp(buf,"+CREG: ",7)==0){
			int res;
			res=sscanf(buf,"+CREG: %d",
				   &creg);
			if(res==1){
				return CREG;
			}
			return ERROR;
		}

		// decode pressed key and type
		if(strncasecmp(buf,"+CKEV: ",7)==0){
			int res;
			res=sscanf(buf,"+CKEV: %1s,%d",
				   key,&type);
			if(res==2){
				return CKEV;
			}
			return ERROR;
		}
		// decode SMS
		if(strncasecmp(buf,"+CMGR: ",7)==0){
			int res;

			res=sscanf(buf,"+CMGR: %d,,%d",
				   &smsstat,&pdulen);
			printf("[BtRCU] Len %d\n",pdulen);
			if(res==2){
				return OK;
			}
			return ERROR;
		}
		
		//decode new incoming SMS
		if(strncasecmp(buf,"+CMTI: ",7)==0){
			int res;
			res=sscanf(buf,"+CMTI: \"%63[^\"]\",%d",
				   smsmem,&smsidx);
			if(res==2){
				return CMTI;
			}
			return ERROR;
		}
		

	}
	if(strcasecmp(buf,"OK")==0){
		return OK;
	}
	if(strcasecmp(buf,"ERROR")==0){
		return ERROR;
	}
	printf("[BtRCU] UNKNOWN");
	return UNKNOWN;
} 

int cBtRCU::send(char * ATCmd ) {
    int r;
    int i = 0;
    r = CONNLOST;
    
    if (fd) {
	printf("[BtRCU] --> %s\n",ATCmd);
	write(fd,"\r\n",2); 
	write(fd, ATCmd, strlen(ATCmd));
	write(fd,"\r\n",2); 
	i = 0;
	do {
	    i++;
	    r = yylex();
	} while ( r != OK && r != ERROR && i < 20 );
    }
    if (r == OK) {
	printf("[BtRCU] Command %s OK\n",ATCmd);
    } else {
    	printf("[BtRCU] Command %s FAILED %d %d\n",ATCmd,r ,i);
    }
    return r;
}

int cBtRCU::yylex() {
	int i;
	if (fd < 0 && ctrl("connecting", rfdevice)) {
	    fd = open(rfdevice, O_RDWR);
	    if (fd >= 0)
	    {
		ctrl("connected", rfdevice);
		printf("[BtRCU] connected\n");
		send("ATZ");
		send("ATE0");
		send("AT+CLIP=1"); // clip

		send("AT+CMER=1,1"); // mobile event reporting, try 1,1
		send("AT+CMER=3,2"); // mobile event reporting, try 3,2
		send("AT+CREG=1");  // network registration reporting
		send("AT+CNMI=1,1");  // display incomming SMS message

		// send("AT+CPMS=ME");  // sms-debugging
		// send("AT+CMGR=41");  // 

	    } 
	    
	}
	for (; fd >= 0;)
	{
    		    for(i=0;i<bufpos;i++){
			if(buf[i]=='\n' || buf[i]=='\r'){
			    int type;
			    buf[i]='\0';
			    type=accept();
			    memmove(buf,buf+i+1,bufpos-i-1);
			    bufpos-=i+1;
			    return type;
			}
		    }
		    i=0;		    
		    if (cFile::FileReady(fd, 1000))
		    {
			i = safe_read(fd, buf + bufpos, BUFFER_SIZE / 16);
		    } else return 0;
		    if (i > 0) {
			bufpos+=i;
		    }
		    else
		    {
			ctrl("lostconnection", rfdevice);
			printf("[BtRCU] lost BT connection\n");
			close(fd);
			fd=-1;
			return CONNLOST;
		    }
	}
	ctrl("disconnected", rfdevice);

	printf("[BtRCU] not connected, waiting 5 seconds\n");
	sleep(5);
	return CONNLOST;
	

}
void cBtRCU::Action()
{
	dsyslog("BtRCU thread started (pid=%d)", getpid());
	printf("[BtRCU] thread started\n");
	int r;
	int i;
	active=1;
	while (active)
	{
		LOCK_THREAD;
		r = yylex();
		switch (r) {
		    case CKEV:
			if (type == 1) {
			    printf("[BtRCU] Key pressed %s\n",key);
			    send("AT+CLCK=CS,2");
			    if (keylock) {
				printf("[BtRCU] OK, passing to Key %s to VDR\n", key);
				Put(key, false);				
			    }	
			}
			
		    break;
		    case CLIP:
			ctrl("clip",clipnr);
		    break;

		    case CREG:
			ctrl("creg",creg);
		    break;
		    case CMTI:
			char *tmp;
			asprintf(&tmp,"AT+CPMS=%s",smsmem);
			send(tmp);
			free(tmp);
			asprintf(&tmp,"AT+CMGR=%d",smsidx);
			send(tmp);
			free(tmp);
		    break;
		    case SMS:
			ctrl("sms",smstext);
		    break;
		    
		    
		}
	}
	if (fd) close(fd);
	printf("[BtRCU] thread ended\n");
	dsyslog("BtRCU thread ended (pid=%d)", getpid());
}
