#include <QCoreApplication>


//#include "ivdriver_lidar_rs16.h"

#include "ivdriver_lidar.h"

#include <signal.h>

#include <getopt.h>
#include <iostream>

#include <iostream>
#include <fstream>
#include <yaml-cpp/yaml.h>

iv::ivmodule * gpivmodule;
QCoreApplication * gpapp;

void sigint_handler(int sig){
    if(sig == SIGINT){
        // ctrl+c退出时执行的代码
        delete gpivmodule;
        gpapp->exit(0);
    }
}
char gstr_memname[256];
char gstr_rollang[256];
char gstr_inclinationang_yaxis[256];  //from y axis
char gstr_inclinationang_xaxis[256];  //from x axis
char gstr_hostip[256];
char gstr_port[256];
char gstr_yaml[256];


void print_useage()
{
    std::cout<<" -m --memname $memname : share memory name. eq.  -m lidar_pc"<<std::endl;
    std::cout<<" -r --rollang $rollang : roll angle. eq.  -r 10.0"<<std::endl;
    std::cout<<" -x --inclinationang_xaxis $inclinationang_xaxis : inclination angle from x axis. eq.  -x 0.0"<<std::endl;
    std::cout<<" -y --inclinationang_yaxis $inclinationang_yaxis : inclination angle from y axis. eq.  -y 0.0"<<std::endl;
    std::cout<<" -o --hostip $hostip : host ip. eq.  -o 192.168.1.111"<<std::endl;
    std::cout<<" -p --port $port : port . eq.  -p 2368"<<std::endl;
    std::cout<<" -s --setyaml $yaml : port . eq.  -s rs1.yaml"<<std::endl;
    std::cout<<" -h --help print help"<<std::endl;
}

int  GetOptLong(int argc, char *argv[]) {
    int nRtn = 0;
    int opt; // getopt_long() 的返回值
    int digit_optind = 0; // 设置短参数类型及是否需要参数

    // 如果option_index非空,它指向的变量将记录当前找到参数符合long_opts里的
    // 第几个元素的描述,即是long_opts的下标值
    int option_index = 0;
    // 设置短参数类型及是否需要参数
    const char *optstring = "m:r:x:y:o:p:s:h";

    // 设置长参数类型及其简写,比如 --reqarg <==>-r
    /*
    struct option {
             const char * name;  // 参数的名称
             int has_arg; // 是否带参数值,有三种:no_argument, required_argument,optional_argument
             int * flag; // 为空时,函数直接将 val 的数值从getopt_long的返回值返回出去,
                     // 当非空时,val的值会被赋到 flag 指向的整型数中,而函数返回值为0
             int val; // 用于指定函数找到该选项时的返回值,或者当flag非空时指定flag指向的数据的值
        };
    其中:
        no_argument(即0),表明这个长参数不带参数(即不带数值,如:--name)
            required_argument(即1),表明这个长参数必须带参数(即必须带数值,如:--name Bob)
            optional_argument(即2),表明这个长参数后面带的参数是可选的,(即--name和--name Bob均可)
     */
    static struct option long_options[] = {
        {"memname", required_argument, NULL, 'm'},
        {"rollang", required_argument, NULL, 'r'},
        {"inclinationang_xaxis", required_argument, NULL, 'x'},
        {"inclinationang_yaxis", required_argument, NULL, 'y'},
        {"hostip", required_argument, NULL, 'o'},
        {"port", required_argument, NULL, 'p'},
        {"setyaml", required_argument, NULL, 's'},
        {"help",  no_argument,       NULL, 'h'},
 //       {"optarg", optional_argument, NULL, 'o'},
        {0, 0, 0, 0}  // 添加 {0, 0, 0, 0} 是为了防止输入空值
    };

    while ( (opt = getopt_long(argc,
                               argv,
                               optstring,
                               long_options,
                               &option_index)) != -1) {
//        printf("opt = %c\n", opt); // 命令参数,亦即 -a -b -n -r
//        printf("optarg = %s\n", optarg); // 参数内容
//        printf("optind = %d\n", optind); // 下一个被处理的下标值
//        printf("argv[optind - 1] = %s\n",  argv[optind - 1]); // 参数内容
//        printf("option_index = %d\n", option_index);  // 当前打印参数的下标值
//        printf("\n");
        switch(opt)
        {
        case 'm':
            strncpy(gstr_memname,optarg,255);
            break;
        case 'r':
            strncpy(gstr_rollang,optarg,255);
            break;
        case 'x':
            strncpy(gstr_inclinationang_xaxis,optarg,255);
            break;
        case 'y':
            strncpy(gstr_inclinationang_yaxis,optarg,255);
            break;
        case 'o':
            strncpy(gstr_hostip,optarg,255);
            break;
        case 'p':
            strncpy(gstr_port,optarg,255);
            break;
        case 's':
            strncpy(gstr_yaml,optarg,255);
            break;
        case 'h':
            print_useage();
            nRtn = 1; //because use -h
            break;
        default:
            break;
        }

    }

    return nRtn;
}

void decodeyaml(const char * stryaml)
{
    YAML::Node config;
    try
    {
        config = YAML::LoadFile(stryaml);
    }
    catch(YAML::BadFile e)
    {
        qDebug("load yaml error.");
        return;
    }


    if(config["memname"])
    {
        strncpy(gstr_memname,config["memname"].as<std::string>().data(),255);
    }
    if(config["rollang"])
    {
        strncpy(gstr_rollang,config["rollang"].as<std::string>().data(),255);
    }
    if(config["inclinationang_xaxis"])
    {
        strncpy(gstr_inclinationang_xaxis,config["inclinationang_xaxis"].as<std::string>().data(),255);
    }
    if(config["inclinationang_yaxis"])
    {
        strncpy(gstr_inclinationang_yaxis,config["inclinationang_yaxis"].as<std::string>().data(),255);
    }
    if(config["hostip"])
    {
        strncpy(gstr_hostip,config["hostip"].as<std::string>().data(),255);
    }
    if(config["port"])
    {
        strncpy(gstr_port,config["port"].as<std::string>().data(),255);
    }



//    std::cout<<gstr_memname<<std::endl;
//    std::cout<<gstr_rollang<<std::endl;
//    std::cout<<gstr_inclinationang_xaxis<<std::endl;
//    std::cout<<gstr_inclinationang_yaxis<<std::endl;
//    std::cout<<gstr_hostip<<std::endl;
//    std::cout<<gstr_port<<std::endl;
}



int lidarmain(iv::ivdriver_lidar * pivm,int argc, char *argv[],QCoreApplication * pa,const char * strmodulename)
{



    int nRtn = GetOptLong(argc,argv);
    if(nRtn == 1)  //show help,so exit.
    {
        return 0;
    }

    if(strnlen(gstr_yaml,255)>0)
    {
        decodeyaml(gstr_yaml);
    }

    strncpy(pivm->mstr_memname,gstr_memname,256);
    strncpy(pivm->mstr_hostip,gstr_hostip,256);
    strncpy(pivm->mstr_port,gstr_port,256);
    pivm->mfrollang = atof(gstr_rollang)*M_PI/180.0;
    pivm->mfinclinationang_xaxis = atof(gstr_inclinationang_xaxis)*M_PI/180.0;
    pivm->mfinclinationang_yaxis = atof(gstr_inclinationang_yaxis)*M_PI/180.0;

    iv::ivmodule * pivmodule = pivm;
    signal(SIGINT, sigint_handler);
    gpivmodule = pivmodule;
    pivmodule->start();
    gpapp = pa;

    return 1;


}