#include    "goahead.h"
#include    "libipmi_IPM.h"
#include    "com_IPMIDefs.h"
#include    "ResultUtils.h"
#include    "cJSON.h"
#include    "libipmi_storlead_OEM.h"
#include    "libsensor.h"
#include    <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <string.h>

/* IWDG */
#define IOCTL_MAGIC 'x' 
#define GENERATE_CMD(__MAGIC__, __MAJOR__, __CMD__) \
    ((0x3<<30) | (__MAJOR__<<16) | (__MAGIC__<<8) | __CMD__)
#define MAJOR_IWDG  108
#define FEED_WATCHDOG                   GENERATE_CMD(IOCTL_MAGIC, MAJOR_IWDG, 0)        
#define START_IWATCHDOG                 GENERATE_CMD(IOCTL_MAGIC, MAJOR_IWDG, 1)        
#define STOP_IWATCHDOG                  GENERATE_CMD(IOCTL_MAGIC, MAJOR_IWDG, 2)    

static uint8_t progress = 0;
static uint8_t target_addr;
/* 进入固件更新模式
* 杀死所有其它进程
*/
void prepareDevice(Webs *wp)
{
    wp->index = TEST_INDEX;
    target_addr = gIPMBAddr[wp->index];
    if(target_addr == 0x20)
    {
        printf("Update Firmware: Prepare Device...\n");
        progress = 0;
        //kill bmc_app
        system("killall -9 damon.sh");
        printf("killall -9 damon.sh\n");
        system("killall -9 bmc_app");
        printf("killall -9 bmc_app\n");
    }
    else
    {
        //Do nothing
    } 

    char *pStr;
    cJSON * root =  cJSON_CreateObject();
    cJSON * data =  cJSON_CreateObject();
    cJSON_AddItemToObject(root, "data", data);//根节点下添加
    cJSON_AddStringToObject(root, "msg", "");
    cJSON_AddNumberToObject(root, "code", 200);
    pStr = cJSON_PrintUnformatted(root);
//    printf("---> cJSON Str:\n%s\n", pStr);
   
    websSetStatus(wp, 200);
    websWriteHeaders(wp, -1, 0);
    websWriteEndHeaders(wp); 
    websWrite(wp,"%s", pStr);
    websFlush(wp, 0);
    // websDone(wp);

    if(pStr)
        wfree(pStr);
    if(root)
        cJSON_Delete(root);
    
    websDone(wp);
    printf("Update Firmware: Prepare Device Ok.\n");
}

/* 
    接收上传的固件
*/

void uploadFirmware(Webs *wp)
{
    WebsKey         *s;
    WebsUpload      *up;
    char            *upfile;

    wp->index = TEST_INDEX;
    target_addr = gIPMBAddr[wp->index];
    if(target_addr == 0x20)
    {
        if (scaselessmatch(wp->method, "POST")) {
            for (s = hashFirst(wp->files); s; s = hashNext(wp->files, s)) {
                up = s->content.value.symbol;
                upfile = sfmt("%s/tmp/%s", websGetDocuments(), "tmp.uImage");
                if (rename(up->filename, upfile) < 0) {
                    error("Cannot rename uploaded file: %s to %s, errno %d", up->filename, upfile, errno);
                }
                wfree(upfile);
            }
          
        }
    }
    else
    {
        //Do nothing
    }

    char *pStr;
    cJSON * root =  cJSON_CreateObject();
    cJSON * data =  cJSON_CreateObject();
    cJSON_AddItemToObject(root, "data", data);//根节点下添加
    cJSON_AddStringToObject(root, "msg", "");
    cJSON_AddNumberToObject(root, "code", 200);
    pStr = cJSON_PrintUnformatted(root);
//    printf("---> cJSON Str:\n%s\n", pStr);
    websSetStatus(wp, 200);
    websWriteHeaders(wp, -1, 0);
    websWriteEndHeaders(wp); 
    websWrite(wp,"%s", pStr);
    websFlush(wp, 0);
    // websDone(wp);

    if(pStr)
        wfree(pStr);
    if(root)
        cJSON_Delete(root);
    
    websDone(wp);
}

/*
    开始执行固件更新
    擦除Flash，写Flash
*/
void updateFlash(Webs *wp)
{
    printf("Update Firmware: Update Flash...\n");
    //TODO: 
    uint8_t cmd[50] = {0};
    progress = 0;

    wp->index = TEST_INDEX;
    target_addr = gIPMBAddr[wp->index];
    if(target_addr == 0x20)
    {
        //Call updateFW_app
        system("/usr/bin/updateFW_app &"); 
        printf("/usr/bin/updateFW_app &"); 
    }
    else
    {
        //Do nothing
    }

    char *pStr;
    cJSON * root =  cJSON_CreateObject();
    cJSON * data =  cJSON_CreateObject();
    cJSON_AddItemToObject(root, "data", data);//根节点下添加
    cJSON_AddStringToObject(root, "msg", "");
    cJSON_AddNumberToObject(root, "code", 200);
    pStr = cJSON_PrintUnformatted(root);
//    printf("---> cJSON Str:\n%s\n", pStr);
   
    websSetStatus(wp, 200);
    websWriteHeaders(wp, -1, 0);
    websWriteEndHeaders(wp); 
    websWrite(wp,"%s", pStr);
    websFlush(wp, 0);
    // websDone(wp);

    if(pStr)
        wfree(pStr);
    if(root)
        cJSON_Delete(root);
    
    websDone(wp);
    printf("Update Firmware: Update Flash ok.\n");
}


/*
    获取Flash更新的进度
    返回 Flash更新的百分比。
*/
void getUpdateProgress(Webs *wp)
{
    uint8_t progressStr[10] = {0};
    FILE *fp;

    wp->index = TEST_INDEX;
    target_addr = gIPMBAddr[wp->index];
    if(target_addr == 0x20)
    {

        //TODO:
        fp = fopen("/var/www/goahead/tmp/UpdateProgress.log", "r");
        if(NULL == fp)
        {
            printf("Open UpdateProgress.log failed!\n");
            websError(wp, 200, "Open UpdateProgress.log failed！");
            return;
        }

        if(NULL == fgets(progressStr, 10, fp))
        {
            printf("Read UpdateProgress.log failed!\n");
            websError(wp, 200, "Read UpdateProgress.log failed！");
            fclose(fp);
            return;
        }
    }
    else
    {
        sprintf(progressStr, "100");
    }

    char *pStr;
    cJSON * root =  cJSON_CreateObject();
    cJSON_AddStringToObject(root, "progress", progressStr);
    cJSON_AddNumberToObject(root, "code", 200);
    

    pStr = cJSON_PrintUnformatted(root);

    websSetStatus(wp, 200);
    websWriteHeaders(wp, -1, 0);
    //websWriteHeader(wp, "getUpdateProgress");
    websWriteEndHeaders(wp);
    websWrite(wp, "%s", pStr);
    websFlush(wp, 0);
    websDone(wp);
    
    if(pStr)
        wfree(pStr);
    if(root)
        cJSON_Delete(root);
}


/*
    获取Flash的校验结果
    返回：Verifying 正在校验
    返回：Verify OK 校验通过
    返回：Verify Error 校验失败
*/
void getVerifyStatus(Webs *wp)
{
    uint8_t verigyStr[13] = {0};
    FILE *fp;

    wp->index = TEST_INDEX;
    target_addr = gIPMBAddr[wp->index];
    if(target_addr == 0x20)
    {
        //TODO:
        fp = fopen("/var/www/goahead/tmp/Verify.log", "r");
        if(NULL == fp)
        {
            printf("Open Verify.log failed!\n");
            websError(wp, 200, "Open Verify.log failed！");
            return;
        }

        if(NULL == fgets(verigyStr, 13, fp))
        {
            printf("Read Verify.log failed!\n");
            websError(wp, 200, "Read Verify.log failed！");
            fclose(fp);
            return;
        }
        
        printf("Update Firmware: %s\n", verigyStr);
    }
    else
    {
        sprintf(verigyStr, "Verify OK");
    }


    char *pStr;
    cJSON * root =  cJSON_CreateObject();
    cJSON_AddStringToObject(root, "verify", verigyStr);
    cJSON_AddNumberToObject(root, "code", 200);
    

    pStr = cJSON_PrintUnformatted(root);

    websSetStatus(wp, 200);
    websWriteHeaders(wp, -1, 0);
    //websWriteHeader(wp, "getUpdateProgress");
    websWriteEndHeaders(wp);
    websWrite(wp, "%s", pStr);
    websFlush(wp, 0);
    websDone(wp);

    if(pStr)
        wfree(pStr);
    if(root)
        cJSON_Delete(root);
}

void resetBmc(Webs *wp)
{
#define DEV_NAME "/dev/platform"
#define IOCTL_MAGIC 'x' 
#define MAJOR_PLATFORM  100
#define GENERATE_CMD(__MAGIC__, __MAJOR__, __CMD__) \
    ((0x3<<30) | (__MAJOR__<<16) | (__MAGIC__<<8) | __CMD__)
#define RESET_MCU                       GENERATE_CMD(IOCTL_MAGIC, MAJOR_PLATFORM, 2)

    printf("Update Firmware: Reset BMC...\n");
    websSetStatus(wp, 200);
    websWriteHeaders(wp, -1, 0);
    websWriteEndHeaders(wp);
    websDone(wp);

    wp->index = TEST_INDEX;
    target_addr = gIPMBAddr[wp->index];
    if(target_addr == 0x20)
    {
        usleep(1000);  //wait previous code
        int fd = open(DEV_NAME, O_RDWR);
        if(fd == -1)
        {
            printf("Open %s failed!\n", DEV_NAME);
        }

        ioctl(fd, RESET_MCU, NULL);    
        close(fd);
    }
}



