#include <sys/prctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "drv_uart_def.h"
#include <gsl/gl_mutex.h>
#include <gsl/gl_task.h>
#include <gsl/gl_timer.h>
#include "al_basictypes.h"
#include "al_console.h"
#include "ap_extern.h"

#include "al_uart_vehicle.h"
#include "al_uart_vehicle_ctrl.h"

int uartbfd = 0;
CON_DEV vehiclecon_dev_t;

extern CON_UART con_uart;
extern pthread_mutex_t uartB_Lock;
extern pthread_cond_t uartB_Strat;
extern al_uint8 bStandby;

pthread_mutex_t uartB_Action = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t uartB_Active = PTHREAD_COND_INITIALIZER;;
pthread_mutex_t reqMutex = PTHREAD_MUTEX_INITIALIZER;

static Vehicle_SendBuffer_t _stvehicleSendBuf;
static Event_LinkList_Node_t *_pstSendvehicleEvtListTail;
static Vehicle_ModCbk_pf g_pfvehicleCallback = NULL;
static GL_Task_t vehicle_DAEMON = NULL;
static GL_Task_t vehicle_LISTENER = NULL;

pCON_DEV get_pVehicleCON_DEV(void)
{
    return &vehiclecon_dev_t;
}

al_uint32 AL_Vehicle_getDecNumFromBCD(al_uint32 bcd)
{
    al_uint32 num;
    int i;
    num = 0;

    for (i = 0; i < 8; i++)
    {
        num *= 10;
        num += (bcd >> (4 * (7 - i)) & 0xf);
    }

    return num;
}

al_uint32 AL_Vehicle_getBCDFromDecNum(al_uint32 num)
{
    al_uint32 bcd;
	int i;
	bcd = 0;
	
	for (i = 0; i < 8; i++)
	{
		bcd |= ((num % 10)&0xf) << (i*4);
		num /= 10;
	}

    return bcd;
}

al_uint8 AL_Vehicle_Get_UARTCmd_CheckSum(al_uint8 * cmdtable, int len)
{
	al_uint8 i = 0;
	int sum = 0;
	
	if(cmdtable == NULL)
		return 0;

	for(i = 1; i < len; i++)
	{
		sum = (sum + cmdtable[i])& 0xFF;
	}
	return sum;
}

void Vehicle_sendCmdToModule(al_uint8 * str, int size)
{
    int count = 0, outsize = 0;
    al_uint len = 0;
    al_uint8 buff[512] = { 0 };

    outsize = size;

    while (1)
    {
        len = (outsize >= UART_BUF_SIZE) ? UART_BUF_SIZE : outsize;
        memcpy(buff, (str + count * UART_BUF_SIZE), len);
        write(uartbfd, buff, len);

        if (outsize > UART_BUF_SIZE)
        {
            count++;
            outsize -= UART_BUF_SIZE;
        }
        else
        {
            break;
        }
    }
}

void Al_Vehicle_Enable(void)
{
    pCON_DEV pcon = &vehiclecon_dev_t;

    pcon->bActive = TRUE;
    CONSOLE_UART_START(UartB);
	bStandby = FALSE;
    pthread_cond_signal(&uartB_Active);
}

void Al_Vehicle_Disable(void)
{
    pCON_DEV pcon = &vehiclecon_dev_t;

    if (!pcon->bActive)
        return;

    pcon->bActive = FALSE;
    con_uart.uartB_Stop = TRUE;

    GL_TaskSleep(50);
}

void Al_Vehicle_Destory(void)
{
    Al_Vehicle_Disable();
    con_uart.uartB_Thread = FALSE;
    Al_Vehicle_Enable();

    pthread_mutex_destroy(&uartB_Lock);
    pthread_mutex_destroy(&uartB_Action);
	pthread_mutex_destroy(&reqMutex);
    pthread_cond_destroy(&uartB_Strat);
    pthread_cond_destroy(&uartB_Active);
}

//send command to ap
Vehicle_Status_e Vehicle_SendEvtToAp(Vehicle_MessageBody_t stEvt)
{
    Event_LinkList_Node_t *pstNew;
	
	pstNew = (Event_LinkList_Node_t *) malloc(sizeof(Event_LinkList_Node_t));
    if (pstNew == NULL)
    {
        return VEHICLE_ERR_FAILURE;
    }
    pstNew->stEvt = stEvt;
	pstNew->stEvt.pdata = (al_uint8 *)malloc(sizeof(al_uint8)*(stEvt.dCmdSize));
	if (pstNew->stEvt.pdata == NULL)
    {
		free(pstNew);
		pstNew = NULL;
        return VEHICLE_ERR_FAILURE;
    }
	memset(pstNew->stEvt.pdata, 0x0, stEvt.dCmdSize);
	memcpy(pstNew->stEvt.pdata, stEvt.pdata, stEvt.dCmdSize);

    if (_stvehicleSendBuf.pstEvtList == NULL)
    {
        _stvehicleSendBuf.pstEvtList = pstNew;
        _pstSendvehicleEvtListTail = pstNew;
        _pstSendvehicleEvtListTail->pstNext = NULL;
    }
    else
    {
        if (_pstSendvehicleEvtListTail)
        {
            _pstSendvehicleEvtListTail->pstNext = pstNew;
            _pstSendvehicleEvtListTail = pstNew;
            _pstSendvehicleEvtListTail->pstNext = NULL;
        }
        else
        {
            free(pstNew->stEvt.pdata);
            free(pstNew);
			pstNew = NULL;
            return VEHICLE_ERR_FAILURE;
        }
    }

    return VEHICLE_SUCCESS;
}

static void _Vehicle_CallbackSendEvt(void)
{	
    //send Event to App
    if (_stvehicleSendBuf.pstEvtList)
    {
        Event_LinkList_Node_t *pEHead = NULL, *pEDel = NULL;
        //printf("%s send event to App\n", __FUNCTION__);
        pEHead = _stvehicleSendBuf.pstEvtList;
        _stvehicleSendBuf.pstEvtList = NULL;
        while (pEHead)
        {
            if (g_pfvehicleCallback != NULL)
            {
                g_pfvehicleCallback(pEHead->stEvt);
            }
            pEDel = pEHead;
            pEHead = pEHead->pstNext;
            free(pEDel->stEvt.pdata);
            free(pEDel);
			pEDel = NULL;
        }
    }
    else
    {
    }
}


void Al_VehicleMainRoutine(void *pParam)
{
    pCON_DEV pcon = &vehiclecon_dev_t;

    prctl(PR_SET_NAME , __FUNCTION__, NULL, NULL, NULL);
    _stvehicleSendBuf.pstEvtList = NULL;
    _stvehicleSendBuf.pstFrmList = NULL;

    while (con_uart.uartB_Thread)
    {
        pthread_mutex_lock(&uartB_Action);
        if (pcon->bActive)
        {
            _Vehicle_CallbackSendEvt();
            _stvehicleSendBuf.pstFrmList = NULL;

        }
        else
        {
            _stvehicleSendBuf.pstEvtList = NULL;
            _stvehicleSendBuf.pstFrmList = NULL;

            pthread_cond_wait(&uartB_Active, &uartB_Action);
        }
        GL_TaskSleep(VEHICLE_DAEMON_DELAY);
        pthread_mutex_unlock(&uartB_Action);
    }
    GL_TaskSelfDelete();

}

static void Vehicle_hanlder(void *arg)
{
    pCON_DEV pconB = &vehiclecon_dev_t;
	
    prctl(PR_SET_NAME , __FUNCTION__, NULL, NULL, NULL);

    do
    {
        pthread_mutex_lock(&uartB_Lock);
        con_uart.uartB_Stop = FALSE;

        pconB->pid = 0;

        if (con_uart.uartB_Thread)
        {
            pthread_cond_wait(&uartB_Strat, &uartB_Lock);
        }

        Al_Vehicle_Listener(pconB);

        pthread_mutex_unlock(&uartB_Lock);
    }
    while (con_uart.uartB_Thread);

    GL_TaskSelfDelete();
    return;
}

void Vehicle_Init(Vehicle_ModualCfg_t * pvehicle_ModualCfg)
{
    pCON_DEV pcon = &vehiclecon_dev_t;

    con_uart.uartB_Thread = TRUE;
    pcon->bActive = FALSE;

    if ((pvehicle_ModualCfg != NULL) && (pvehicle_ModualCfg->pfCallBack != NULL))
    {
        g_pfvehicleCallback = pvehicle_ModualCfg->pfCallBack;
    }

    if (GL_TaskCreate("vehicle Daemon", (void *) Al_VehicleMainRoutine, NULL, 3, 4096, TRUE, &(vehicle_DAEMON)) != GL_SUCCESS)
        printf("pthread_create fail: Al_vehicleMainRoutine thread\n");


    if (GL_TaskCreate("vehicle Listener", (void *) Vehicle_hanlder, NULL, 3, 4096, TRUE, &(vehicle_LISTENER)) != GL_SUCCESS)
        printf("pthread_create fail: vehicle_hanlder thread\n");
}
