#include <sys/poll.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <time.h>
#include <pthread.h>
#include "hiredis/hiredis.h"
#include "cjson/cJSON.h"
#include "iniparser/iniparser.h"

#define Boolean int
#define TRUE 1
#define FALSE 0
#define MAX_PIPE_BUFSIZE    32
//GPIO_STATUS
#define GPIO_Off     0
#define GPIO_On      1
#define GPIO_Fast    2
#define GPIO_Slow    3
#define GPIO_Simultaneously 4
#define GPIO_Alternately    5

#define SPK_CONF    "/etc/speaker.conf"
#define unix_socket_path "/tmp/redis.sock"
#define VAR_IP      "${ip}"
#define VAR_MAC     "${mac}"

static int DEBUG = FALSE;
static int GPIO67_STATUS = GPIO_Off;
static int GPIO135_STATUS = GPIO_Off;


int GetCmdValue(char *file, char *key, char *value, int lenth)
{
	dictionary  *   ini ;
	ini = iniparser_load(file);
	
    if (ini==NULL) {
        fprintf(stderr, "cannot parse file: %s\n", file);
        return FALSE ;
    }
	strcpy(value, iniparser_getstring(ini, key, ""));
	if(DEBUG)
		printf("keystr: \"%s\" ; value: %s.\n", key, value);
	iniparser_freedict(ini);
	return TRUE;
}

char *strrpl(char *s, const char *s1, const char *s2)
{
    char *ptr;
    while (ptr = strstr(s, s1)) /* 如果在s中找到s1 */
    {
        memmove(ptr + strlen(s2) , ptr + strlen(s1), strlen(ptr) - strlen(s1) + 1);
        memcpy(ptr, &s2[0], strlen(s2));
    }
    return s;
}

Boolean get_ip(char * pv)
{
        FILE * fp;
        char cmdbuf[128], value[32];
        char *tmp=NULL;
        sprintf(cmdbuf,"/sbin/ifconfig eth0 | grep inet | cut -d\":\" -f2 | cut -d\" \" -f1");
        fp = popen(cmdbuf, "r");
        if (fp == NULL) {
                // printf("Fail to open pipe\n");
                return FALSE;
        }

        memset(value,0,sizeof(value));

        if (!feof(fp) && fgets(value,MAX_PIPE_BUFSIZE,fp) != NULL)
            ;
            // printf("value:%s\n", value);
        else {
            printf("ip wrong\n");
            return FALSE;
        }

        pclose(fp);

        if(strlen(value) < 10)
            return FALSE;
        if(tmp = strstr(value,"\n"))
        {
            *tmp = '\0';
        }
        strcpy(pv,value);
        return TRUE;
}

Boolean get_mac(char * pv)
{
        FILE * fp;
        char cmdbuf[128], value[32];
        char *tmp=NULL;
        sprintf(cmdbuf,"ifconfig eth0 | grep HWaddr | tr -d : | awk '{print $5}'");
        fp = popen(cmdbuf, "r");
        if (fp == NULL) {
                // printf("Fail to open pipe\n");
                return FALSE;
        }

        memset(value,0,sizeof(value));

        if (!feof(fp) && fgets(value,MAX_PIPE_BUFSIZE,fp) != NULL)
            ;
            // printf("value:%s\n", value);
        else {
            printf("ip wrong\n");
            return FALSE;
        }

        pclose(fp);

        if(strlen(value) < 10)
            return FALSE;
        if(tmp = strstr(value,"\n"))
        {
            *tmp = '\0';
        }
        strcpy(pv,value);
        return TRUE;
}

void action_url(char *url)
{
    char cmd[320];
    sprintf(cmd,"curl --connect-timeout 5 '%s' 2>/dev/null &",url);
    if(DEBUG)
        printf( "Command: %s\n", cmd);
    system(cmd);
}

int get_gpio_type(char *output_type){

    if(strcmp(output_type, "On") == 0)
    {
        return GPIO_On;
    }
    else if(strcmp(output_type, "FastFlashing") == 0)
    {
        return GPIO_Fast;
    }
    else if(strcmp(output_type, "SlowFlashing") == 0)
    {
        return GPIO_Slow;
    }
    else if(strcmp(output_type, "Simultaneously") == 0)
    {
        return GPIO_Simultaneously;
    }
    else if(strcmp(output_type, "Alternately") == 0)
    {
        return GPIO_Alternately;
    }
    

    return GPIO_Off;
}

void gpio_on_trigger()
{
    char enable[8],url[256],ipaddr[16],macaddr[16],cmd[320];
    GetCmdValue(SPK_CONF, "relay_action_url:on_enable", enable, sizeof(enable));
    if(strcmp(enable,"yes") == 0)
    {
        GetCmdValue(SPK_CONF, "relay_action_url:on_url", url, sizeof(url));
        if(strstr(url,VAR_IP))
        {
            if(get_ip(ipaddr))
                strcpy(url, strrpl(url, VAR_IP, ipaddr));
        }
        if(strstr(url,VAR_MAC))
        {
            if(get_mac(macaddr))
                strcpy(url, strrpl(url, VAR_MAC, macaddr));
        }
        action_url(url);
    }
}

void gpio_off_trigger()
{
    char enable[8],url[256],ipaddr[16],macaddr[16],cmd[320];
    GetCmdValue(SPK_CONF, "relay_action_url:off_enable", enable, sizeof(enable));
    if(strcmp(enable,"yes") == 0)
    {
        GetCmdValue(SPK_CONF, "relay_action_url:off_url", url, sizeof(url));
        if(strstr(url,VAR_IP))
        {
            if(get_ip(ipaddr))
                strcpy(url, strrpl(url, VAR_IP, ipaddr));
        }
        if(strstr(url,VAR_MAC))
        {
            if(get_mac(macaddr))
                strcpy(url, strrpl(url, VAR_MAC, macaddr));
        }
        action_url(url);
    }
}

//gpio控制指令处理
void ProcessReply( redisReply * pReply )
{
    cJSON *pJson = NULL;
    redisReply * pSubReply = NULL;

    if ( pReply->elements == 2 )
    {
        pSubReply = pReply->element[1];
        if(DEBUG)
            printf( "Msg [%s]\n", pSubReply->str );
        pJson =  cJSON_Parse(pSubReply->str);
        if ( pJson ) {
            if(strcmp(cJSON_GetObjectItem(pJson, "id")->valuestring, "gpio67") == 0 || strcmp(cJSON_GetObjectItem(pJson, "id")->valuestring, "gpio135") == 0)
            {
                GPIO67_STATUS = get_gpio_type(cJSON_GetObjectItem(pJson, "type")->valuestring);
                if(GPIO67_STATUS == GPIO_Off)
                {
                    gpio_off_trigger();
                }
                else
                {
                    gpio_on_trigger();
                }
                if(DEBUG)
                    printf("RLEAY: %s\n",cJSON_GetObjectItem(pJson, "type")->valuestring);
            }
        }else{
            printf( "parse failed!\n");
        }
        if(pJson != NULL) cJSON_Delete(pJson);
    }
}

/*
* 接收控制指令.
*/
void *get_gpio_control()
{
    redisContext * pContext = redisConnectUnix(unix_socket_path);

    if ( NULL == pContext || pContext->err == 1 )
    {
        printf( "%s\n", pContext->errstr );
        exit( -1 );
    }

    char * pKey = "output-channel";
    redisReply * pReply;
    while(1){
        pReply = NULL;
        pReply = redisCommand( pContext, "BRPOP %s 60", pKey );
		if(pReply != NULL && pReply->type == REDIS_REPLY_ARRAY){
			ProcessReply( pReply );
		}
		if(pReply != NULL) freeReplyObject( pReply );
        usleep(500*1000);
    }
    redisFree( pContext );
}

//gpio状态设置
void *gpio_status()
{
    int gpioFlashTime = 0,gpioFlashTag1 = 0,gpioFlashTag2 = 0;
    while(1)
    {
        usleep(10 * 1000);
        /*	gpio flash controller	*/
        gpioFlashTime++;

        if(gpioFlashTime == 47 || gpioFlashTime == 143){
            if(GPIO67_STATUS == GPIO_On)
                system("echo 1 > /sys/class/gpio/gpio112/value");
            else if(GPIO67_STATUS == GPIO_Off)
                system("echo 0 > /sys/class/gpio/gpio112/value");
        }

        if(gpioFlashTime % 39 == 0){
            if(GPIO67_STATUS == GPIO_Fast){
                gpioFlashTag2 = !gpioFlashTag2;
                if(gpioFlashTag2){
                    system("echo 0 > /sys/class/gpio/gpio112/value");
                }else{
                    system("echo 1 > /sys/class/gpio/gpio112/value");
                }
            }
        }

        if(gpioFlashTime % 99 == 0){
            if(GPIO67_STATUS == GPIO_Slow){
                gpioFlashTag2 = !gpioFlashTag2;
                if(gpioFlashTag2){
                    system("echo 0 > /sys/class/gpio/gpio112/value");
                }else{
                    system("echo 1 > /sys/class/gpio/gpio112/value");
                }
            }
        }
            
        /*	restart the led flash loop	*/
        if(gpioFlashTime == 200)
            gpioFlashTime = 0;
    }
}

int main(int argc, char *argv[]){
    char model[16];
    int ret_thrd1,ret_thrd2;
    pthread_t thread1, thread2;

    if(argc == 2 && strcmp(argv[1], "debug") == 0)
        DEBUG = TRUE;

    //启动线程控制gpio状态
    ret_thrd2 = pthread_create(&thread2, NULL, gpio_status, NULL);
    if (ret_thrd2 != 0) {
        printf("create thread2 gpio_status failed\n");
        return 0;
    }

    //启动线程接收gpio控制指令
    get_gpio_control();
}