#include "ltr/include/ltrapi.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef _WIN32
#include <locale.h>
#include <conio.h>
#else
#include <signal.h>
#include <unistd.h>
#endif

#define TMARK_TYPE_SEL      LTR_MARK_SEC_IRIGB_DIGIN1


typedef struct {
    int slot;
    const char *serial;
    DWORD addr;
} t_open_param;


/* признак необходимости завершить сбор данных */
static int f_out = 0;

#ifndef _WIN32
/* Обработчик сигнала завершения для Linux */
static void f_abort_handler(int sig) {
    f_out = 1;
}
#endif


/* Разбор параметров командной строки. Если указано меньше, то используются
 * значения по умолчанию:
 * 1 параметр - номер слота (от 1 до 16)
 * 2 параметр - серийный номер крейта
 * 3 параметр - ip-адрес сервера */
static int f_get_params(int argc, char** argv, t_open_param* par) {
    int err = 0;
    par->slot = LTR_CC_CHNUM_MODULE1;
    par->serial = "";
    par->addr = LTRD_ADDR_DEFAULT;


    if (argc > 1)
        par->slot = atoi(argv[1]);
    if (argc > 2)
        par->serial = argv[2];
    if (argc > 3) {
        int a[4],i;
        if (sscanf(argv[3], "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3])!=4) {
            fprintf(stderr, "Неверный формат IP-адреса!!\n");
            err = -1;
        }

        for (i=0; (i < 4) && !err; i++) {
            if ((a[i]<0) || (a[i] > 255)) {
                fprintf(stderr, "Недействительный IP-адрес!!\n");
                err = -1;
            }
        }

        if (!err) {
            par->addr = (a[0] << 24) | (a[1]<<16) | (a[2]<<8) | a[3];
        }
    }
    return err;
}


/* устанавливаем соединение с любым непустым слотом и начинаем считывать данные.
 * если для этого модуля не был отдельно запущен сбор, то размер
 * принимаемых данных будет всегда 0, но при этом значение метки
 * unixtime будет все равно обновляться */
static int f_read_unixtime(t_open_param *pars) {
    TLTR ltrmodule;
    INT err = LTR_OK;


    LTR_Init(&ltrmodule);
    if (pars->serial!=NULL) {
        strncpy(ltrmodule.csn, pars->serial, LTR_CRATE_SERIAL_SIZE);
        ltrmodule.csn[LTR_CRATE_SERIAL_SIZE-1] = '\0';
    }
    ltrmodule.saddr = pars->addr;
    ltrmodule.cc = pars->slot;
    err = LTR_Open(&ltrmodule);
    if (err!=LTR_OK) {
        fprintf(stderr, "Невозможно установить связь с модулем! Ошибка %d: %s\n",
               err, LTR_GetErrorString(err));
    } else {
        LONGLONG prev_unixtime = 0;
        printf("Запущен прием меток unixtime. Для останова нажмите %s\n",
#ifdef _WIN32
               "любую клавишу"
#else
               "CTRL+C"
#endif
               );
        fflush(stdout);


        while ((err==LTR_OK) && !f_out) {
            LONGLONG unixtime;
            DWORD buf[1024];
            INT recv_res;


            recv_res = LTR_Recv(&ltrmodule, buf, NULL, sizeof(buf)/sizeof(buf[0]), 250);
            if (recv_res < 0) {
                err = recv_res;
                fprintf(stderr, "Ошибка чтения данных из модуля! Ошибка %d: %s\n",
                       err, LTR_GetErrorString(err));
            }

            if (err == LTR_OK) {
                err = LTR_GetLastUnixTimeMark(&ltrmodule, &unixtime);
                if (err != LTR_OK) {
                    fprintf(stderr, "Ошибка получения последней метки unixtime! Ошибка %d: %s\n",
                           err, LTR_GetErrorString(err));
                }
            }

            if ((err == LTR_OK) && (unixtime != prev_unixtime)) {
                time_t t_val = (time_t)unixtime;
                printf("\r%s", ctime(&t_val));
                fflush(stdout);
                prev_unixtime = unixtime;
            }

#ifdef _WIN32
            /* проверка нажатия клавиши для выхода */
            if (err==LTR_OK) {
                if (_kbhit())
                    f_out = 1;
            }
#endif
        }

        LTR_Close(&ltrmodule);
    }
    return err;
}





int main(int argc, char **argv) {
   INT err;
   t_open_param par;
#ifndef _WIN32
   struct sigaction sa;
   memset(&sa, 0, sizeof(sa));
   /* В ОС Linux устанавливаем свой обработчик на сигнал закрытия,
      чтобы завершить сбор корректно */
   sa.sa_handler = f_abort_handler;
   sigaction(SIGTERM, &sa, NULL);
   sigaction(SIGINT, &sa, NULL);
   sigaction(SIGABRT, &sa, NULL);
#endif

#ifdef _WIN32
   /* для вывода русских букв в консоль для ОС Windows*/
   setlocale(LC_ALL, "");
#endif

   err = f_get_params(argc, argv, &par);

   if (err==LTR_OK) {
       TLTR hcrate;
       LTR_Init(&hcrate);
       err = LTR_OpenCrate(&hcrate, par.addr, LTRD_PORT_DEFAULT, LTR_CRATE_IFACE_UNKNOWN, par.serial);
       if (err!=LTR_OK) {
           fprintf(stderr, "Невозможно установить связь с крейтом! Ошибка %d: %s\n",
                  err, LTR_GetErrorString(err));
       } else {
           TLTR_CONFIG cfg;
           unsigned int i;

           /* настройка выходов разъема LTR-EU для индикации IRIG
            * (можно и не использовать, если выходы нужны для другого) */
           for (i=0; i < sizeof(cfg.digout)/sizeof(cfg.digout[0]); i++)
               cfg.digout[i] = LTR_DIGOUT_IRIG;
           for (i=0; i < sizeof(cfg.userio)/sizeof(cfg.userio[0]); i++)
               cfg.userio[i] = LTR_USERIO_DIGOUT;
           cfg.digout_en = 1;

           err = LTR_Config(&hcrate, &cfg);
           if (err!=LTR_OK) {
               fprintf(stderr, "Не удалось сконфигурировать крейт! Ошибка %d: %s\n",
                      err, LTR_GetErrorString(err));
           }

           if (err==LTR_OK) {
               err = LTR_StartSecondMark(&hcrate, TMARK_TYPE_SEL);
               if (err!=LTR_OK) {
                   fprintf(stderr, "Не удалось запустить синхрометки! Ошибка %d: %s\n",
                          err, LTR_GetErrorString(err));
               }


               f_read_unixtime(&par);

               if (err==LTR_OK) {
                   err = LTR_StopSecondMark(&hcrate);
                   if (err!=LTR_OK) {
                       fprintf(stderr, "Не удалось остановить синхрометки! Ошибка %d: %s\n",
                              err, LTR_GetErrorString(err));
                   } else {
                       printf("Генерация меток остановлена\n");
                   }
               }
           }

           LTR_Close(&hcrate);
       }
   }
   return -err;
}
