/***************************************************************************
 * C++ Implementation:                                                     *
 * Copyright (C) 2012-2017 by Eduard Kalinowski                            *
 * Germany, Lower Saxony, Hanover                                          *
 * eduard_kalinowski@yahoo.de                                              *
 *                                                                         *
 * HTTraQt is free software; may be distributed and/or modified under the  *
 * terms of the GNU General Public License version 3 as published by the   *
 * Free Software Foundation and appearing in the file LICENSE_GPLv3        *
 * included in the packaging of this file.                                 *
 *                                                                         *
 * This program is distributed in the hope that it will be useful,         *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 * GNU General Public License for more details.                            *
 *                                                                         *
 * You should have received a copy of the GNU Lesser General Public        *
 * License along with HTTraQt. If not, see  http://www.gnu.org/licenses    *
 ***************************************************************************/


#include "includes/httraqt.h"
#include "includes/ProgressTab.h"

#ifdef __cplusplus
extern "C"
{
#endif

#include "includes/htinterface.h"


#include <httrack-library.h>
#include <htsglobal.h>
#include <htswrap.h>
#include <htsopt.h>
#include <htsdefines.h>


#ifdef __cplusplus
}
#endif


extern HTTraQt* mainWidget;

class MainWindow;


void __cdecl wrapper_init(t_hts_callbackarg * carg)
{
    //printf("Engine started\n");
    //   mirror_info("Engine started");
    wrapper_loop(NULL, NULL, NULL, 0, 0, 0, 0, 0, 0);
}


const char* __cdecl wrapper_query(t_hts_callbackarg* carg, httrackp *opt, const char* question)
{
    //char* __cdecl htsshow_query(char* question) {
    QString q = QString("%1Press <Y><Enter> to confirm, <N><Enter> to abort").arg(question);

    int ans = MessageBox::exec(NULL, cTranslator::translate(_QUEST), q, QMessageBox::Question);

    if (ans == QMessageBox::Yes) {
        return (char*)"Y";
    }

    return (char*)"N";
}


const char* __cdecl wrapper_query2(t_hts_callbackarg* carg, httrackp *opt, const char* question)
{
    //char* __cdecl htsshow_query(char* question) {
    QString q = QString("%1Press <Y><Enter> to confirm, <N><Enter> to abort").arg(question);

    int ans = MessageBox::exec(NULL, cTranslator::translate(_QUEST), q, QMessageBox::Question);

    if (ans == QMessageBox::Yes) {
        return (char*)"Y";
    }

    return (char*)"N";
}


const char* __cdecl wrapper_query3(t_hts_callbackarg* carg, httrackp *opt, const char* question)
{
    //char* __cdecl htsshow_query(char* question) {
    QString q = QString("%1Press <Y><Enter> to confirm, <N><Enter> to abort").arg(question);

    int ans = MessageBox::exec(NULL, cTranslator::translate(_QUEST), q, QMessageBox::Question);

    if (ans == QMessageBox::Yes) {
        return (char*)"Y";
    }

    return (char*)"N";
}


int __cdecl wrapper_check(t_hts_callbackarg* carg, httrackp *opt, const char* adr, const char* fil, int status)
{
    /* testprgm** printf("Link status tested: http://%s%s\n",adr,fil);
    mirror_testc("Link status tested"); */
    return -1;
}


int __cdecl wrapper_check_mime(t_hts_callbackarg* carg, httrackp *opt, const char* adr, const char* fil, const char* mime, int status) // appelé par le wizard
{
    //     ATLTRACE(__FUNCTION__ " : check %s%s : <%s>\r\n", adr, fil, mime);
    return -1;
}


void __cdecl wrapper_pause(t_hts_callbackarg* carg, httrackp *opt, const char* lockfile)
{
    //void __cdecl htsshow_pause(char* lockfile) {
    while (QFile::exists(lockfile)) {
        sleep(1000);
    }
}


void __cdecl wrapper_filesave(t_hts_callbackarg* carg, httrackp *opt, const char* file)
{
}


void __cdecl wrapper_filesave2(t_hts_callbackarg* carg, httrackp *opt, const char* adr, const char* fil, const char* save, int is_new, int is_modified, int not_updated)
{
    //     ATLTRACE(__FUNCTION__ " : saving %s%s as %s (new=%d, modified=%d, notupdated=%d)\r\n", adr, fil, save, is_new, is_modified, not_updated);
}


// void htcommandend(void)
// {
//     qDebug() << "htcommandend";
//     mainWidget->endMirror();
// }


void *pth_showlog(void *threadid)
{
    char commande[1024] ;
    //     sprintf(commande, "kwrite %s/%s/hts-log.txt &\n",
    //             kMirrorViewGlobal->project->s_project.gene_projectPath,
    //             kMirrorViewGlobal->project->s_project.gene_projectName);
    //     printf(commande);
    //     system(commande);
    //     pthread_exit(NULL);
}


int __cdecl wrapper_linkdetected(t_hts_callbackarg * carg, httrackp * opt,
                                 char *link)
{
    return 1;
}


int __cdecl wrapper_linkdetected2(t_hts_callbackarg * carg, httrackp * opt,
                                  char *link, const char *start_tag)
{
    return 1;
}


int __cdecl wrapper_xfrstatus(t_hts_callbackarg * carg, httrackp * opt,
                              lien_back * back)
{
    return 1;
}


int __cdecl wrapper_savename(t_hts_callbackarg * carg, httrackp * opt,
                             const char *adr_complete, const char *fil_complete,
                             const char *referer_adr, const char *referer_fil,
                             char *save)
{
    return 1;
}


int __cdecl wrapper_sendheader(t_hts_callbackarg * carg, httrackp * opt,
                               char *buff, const char *adr, const char *fil,
                               const char *referer_adr, const char *referer_fil,
                               htsblk * outgoing)
{
    return 1;
}


int __cdecl wrapper_receiveheader(t_hts_callbackarg * carg, httrackp * opt,
                                  char *buff, const char *adr, const char *fil,
                                  const char *referer_adr,
                                  const char *referer_fil, htsblk * incoming)
{
    return 1;
}


void __cdecl wrapper_uninit(t_hts_callbackarg *carg)
{
    //printf("Engine exited\n");
    htinfo_mirror_info((char*)"Engine exited");

    //     htcommandend();
    // #ifdef _WIN32
    //     WSACleanup();
    // #endif
}


//
int __cdecl wrapper_start(t_hts_callbackarg *carg, httrackp *opt)
{
    htinfo_mirror_info((char*)"Started");

    //   use_show=0;

    if (mainWidget->global_opt->verbosedisplay == 2) {
        //     use_show=1;
        //einbauen status display crear
        // vt_clear();
    }

    return 1;
}


int __cdecl wrapper_chopt(t_hts_callbackarg* carg, httrackp *opt)
{
    return wrapper_start(carg, opt);
}


int __cdecl wrapper_preprocesshtml(t_hts_callbackarg* carg, httrackp *opt, char** html, int* len, const char* url_address, const char* url_file)
{
    //     ATLTRACE(__FUNCTION__ " : preprocessing %s%s (%d bytes)\r\n", url_address, url_file, *len);
    return 1;
}


int __cdecl wrapper_postprocesshtml(t_hts_callbackarg* carg, httrackp *opt, char** html, int* len, const char* url_address, const char* url_file)
{
    //     ATLTRACE(__FUNCTION__ " : postprocessing %s%s (%d bytes)\r\n", url_address, url_file, *len);
    //char *old = *html;
    //*html = hts_strdup(*html);
    //hts_free(old);
    return 1;
}


int  __cdecl wrapper_end(t_hts_callbackarg* carg, httrackp *opt)
{
    htinfo_mirror_info((char*)cTranslator::translate(_ENDMIRROR).data());
    // qDebug() << "termine after htinfo_mirror_info";
    mainWidget->termine = 1;

    return 1;
}


int __cdecl wrapper_checkhtml(t_hts_callbackarg * carg, httrackp * opt,
                              char *html, int len, const char *url_address,
                              const char *url_file)
{
    return 1;
    char chaine[1024] ;
    sprintf(chaine, "%s%s", url_address, url_file);
    //printf("Parsing html file \"%s\": http://%s%s\n",html,url_adresse,url_fichier);
    htinfo_state_url(chaine);
    return 1;
}


void __cdecl htinfo_mirror_info(char *c)
{
    // status
}


// called each loop of HTTrack
int __cdecl wrapper_loop(t_hts_callbackarg* carg, httrackp *opt, lien_back* back, int back_max, int back_index, int lien_tot,  int lien_ntot, int stat_time, hts_stat_struct* stats)
{
    static TStamp prev_mytime = 0; /* ok */
    TStamp mytime;
    long int rate = 0;
    //     char st[256];
    //
    int stat_written = -1;
    int stat_updated = -1;
    int stat_errors = -1;
    int stat_warnings = -1;
    int stat_infos = -1;
    int nbk = -1;
    //     LLint nb = -1;
    int stat_nsocket = -1;
    LLint stat_bytes = -1;
    LLint stat_bytes_recv = -1;
    int irate = -1;


    ASSERT(stats)

    if (stats) {
        stat_written = stats->stat_files;
        stat_updated = stats->stat_updated_files;
        stat_errors = stats->stat_errors;
        stat_warnings = stats->stat_warnings;
        stat_infos = stats->stat_infos;
        nbk = stats->nbk;
        stat_nsocket = stats->stat_nsocket;
        irate = (int) stats->rate;
        //         nb = stats->nb;
        stat_bytes = stats->nb;
        stat_bytes_recv = stats->HTS_TOTAL_RECV;
    }

    //   if (!mainWidget->use_show)
    //         return 1;
    //   qDebug() << "max" << back_max << "index"<<  back_index;

    if (back_max == 0) {
        // en cas de manque de time
        mainWidget->SInfo.refresh = 1;//back_index;
        mainWidget->SInfo.stat_timestart = mtime_local();
        return 1;
    }

    if (mainWidget->termine || mainWidget->termine_requested) {
        mainWidget->SInfo.refresh = 0;    // pas de refresh
        mainWidget->termine_requested = 1;
        return 0;
    }

    if (stat_written >= 0) {
        mainWidget->SInfo.stat_written = stat_written;
    }

    if (stat_updated >= 0) {
        mainWidget->SInfo.stat_updated = stat_updated;
    }

    if (stat_errors >= 0) {
        mainWidget->SInfo.stat_errors = stat_errors;
    }

    if (stat_warnings >= 0) {
        mainWidget->SInfo.stat_warnings = stat_warnings;
    }

    if (stat_infos >= 0) {
        mainWidget->SInfo.stat_infos = stat_infos;
    }

    //     if (!mainWidget->SInfo.ask_refresh) {
    //         return 0;
    //     }

    // initialiser ft
    if (stat_nsocket == -1) {
        if (mainWidget->SInfo.ft == -1) {
            mainWidget->SInfo.ft = stat_time;
        }
    }

    mytime = mtime_local();

    if (stat_time < 0) {
        mainWidget->SInfo.stat_time = (int)(mytime - mainWidget->SInfo.stat_timestart);
    }

    if ((stat_time > 0) && (stat_bytes_recv > 0)) {
        rate = (int)(stat_bytes_recv / stat_time);
    } else {
        rate = 0;    // pas d'infos
    }

    /* Infos */
    if (stat_bytes >= 0) {
        mainWidget->SInfo.stat_bytes = stat_bytes;    // bytes
    }

    if (stat_time >= 0) {
        mainWidget->SInfo.stat_time = stat_time;    // time
    }

    if (lien_tot >= 0) {
        mainWidget->SInfo.lien_tot = lien_tot;    // nb liens
    }

    if (lien_ntot >= 0) {
        mainWidget->SInfo.lien_n = lien_ntot;    // scanned
    }

    mainWidget->SInfo.stat_nsocket = stat_nsocket;        // socks

    if (rate > 0) {
        mainWidget->SInfo.rate = rate;    // rate
    }

    if (irate >= 0) {
        mainWidget->SInfo.irate = irate;    // irate
    }

    if (mainWidget->SInfo.irate < 0) {
        mainWidget->SInfo.irate = mainWidget->SInfo.rate;
    }

    if (nbk >= 0) {
        mainWidget->SInfo.stat_back = nbk;
    }

    strc_int2bytes2 strc, strc2, strc3;

    if ((((mytime - prev_mytime) > 100) || ((mytime - prev_mytime) < 0))) {
        //         return (mainWidget->termine == 0);
        //     }

        prev_mytime = mytime;

        //     st[0] = '\0';
        //
        //     qsec2str(st, stat_time);
        mainWidget->mutex.lock();

        // parcourir registre des liens
        if (back_index >= 0) {    // seulement si index pass�
            //             mainWidget->SInfo.refresh = 1; // ???
            //             return (mainWidget->termine == 0);
            //         }

            //     mainWidget->clearStatsBuffer();

            int index = 0;
            //   bool ok = false;       // idem

            // becouse we write into mainWidget->StatsBuffer


            mainWidget->clearStatsBuffer();

            // back_index is number of "Sockets", also max number of rows in the progressbar for displaying
            for (int k = 0; k < 2; k++) {   // 0: aktuelle verbindung 1: andere verbindungen
                for (int j = 0; (j < 3) && (index < NStatsBuffer); j++) {       // durchgang der priorität
                    int max = 1;

                    if ((back_max * k) > max) {
                        max = back_max * k;
                    }

                    for (int _i = 0 + k; (_i < max) && (index < NStatsBuffer); _i++) { // nummer der verbindung
                        int i = (back_index + _i) % back_max;    // anfang vom "ersten"

                        if (back[i].status < 0) {    // signifie "lien actif"
                            continue;
                        }

                        // if (strlen(back[i].url_fil) > 0){
                        //     qDebug() << "status " << (int)back[i].status << " name " << back[i].url_fil << " i=" << i << endl;
                        // }
                        bool ok = false;

                        switch (j) {
                            case 0:  {   // prioritaire
                                if ((back[i].status > 0) && (back[i].status < 99)) {
                                    mainWidget->StatsBuffer[index].strStatus = cTranslator::translate(_RECEIVE);
                                    ok = true;
                                }

                                break;
                            }

                            case 1: {
                                switch (back[i].status) {
                                    case STATUS_WAIT_HEADERS: { // 99
                                        mainWidget->StatsBuffer[index].strStatus = cTranslator::translate(_REQUEST);
                                        ok = true;
                                        break;
                                    }

                                    case STATUS_CONNECTING: {  // 100
                                        mainWidget->StatsBuffer[index].strStatus = cTranslator::translate(_CONNECT);
                                        ok = true;
                                        break;
                                    }

                                    case STATUS_WAIT_DNS: {  // 101
                                        mainWidget->StatsBuffer[index].strStatus = cTranslator::translate(_SEARCH);
                                        ok = true;
                                        break;
                                    }

                                    case STATUS_FTP_TRANSFER: {   // 1000
                                        mainWidget->StatsBuffer[index].strStatus = QString("ftp: %1").arg(back[i].info);
                                        ok = true;
                                        break;
                                    }

                                    case STATUS_SSL_WAIT_HANDSHAKE: {       // 102
                                        mainWidget->StatsBuffer[index].strStatus = cTranslator::translate(_CONNECT);
                                        ok = true;
                                        break;
                                    }

                                    case STATUS_ALIVE: {       // waiting (keep-alive)
                                        mainWidget->StatsBuffer[index].strStatus = cTranslator::translate(_WAITING);
                                        ok = true;
                                        break;
                                    }

                                    default:
                                        //qDebug() << "1 status" << back[i].status  <<  back[i].url_fil;
                                        break;
                                }

                                break;
                            }

                            default: {
                                if (back[i].status == STATUS_READY) {    // STATUS_READY
                                    if ((back[i].r.statuscode == HTTP_OK)) {
                                        mainWidget->StatsBuffer[index].strStatus = cTranslator::translate(_READY);
                                        ok = true;
                                    } else if ((back[i].r.statuscode >= 100) && (back[i].r.statuscode <= 599)) {
                                        char tempo[256];
                                        tempo[0] = '\0';
                                        infostatuscode(tempo, back[i].r.statuscode);
                                        mainWidget->StatsBuffer[index].strStatus = tempo;
                                        ok = true;
                                    } else {
                                        //                                         mainWidget->StatsBuffer[index].strStatus = cTranslator::translate(_ERROR);
                                        //                                                                                 ok = true;
                                    }
                                }

                                break;
                            }
                        }

                        if (ok) {
                            QString s = "";
                            //if (strlen(back[i].url_fil) > 0){
                            //    qDebug() << "k=" << k << "j=" << j << "status:" << back[i].status << "name" << back[i].url_fil << "totalsize" << back[i].r.totalsize << "size" << back[i].r.size;
                            //}

                            mainWidget->StatsBuffer[index].back = i;      // index pour + d'infos
                            mainWidget->StatsBuffer[index].url_sav = back[i].url_sav; // pour cancel

                            if (strcmp(back[i].url_adr, "file://")) {
                                s += back[i].url_adr;
                            } else {
                                s += "localhost";
                            }

                            if (back[i].url_fil[0] != '/') {
                                s += "/";
                            }

                            s += back[i].url_fil;

                            mainWidget->StatsBuffer[index].file = "";
                            int pos;
                            pos = s.lastIndexOf('/');

                            if (pos >= 0) {
                                QString nm = s.mid(pos + 1);

                                if (nm.length() == 0) {
                                    if (s != "/") {
                                        nm = s;
                                    } else {
                                        s = "";
                                    }

                                    //else{
                                    //    qDebug() << "url addr" << back[i].url_adr << "file" << back[i].url_fil;
                                    //}
                                }

                                if (nm.length() > MAX_LEN_INPROGRESS) { // couper
                                    nm = nm.left(16) + "..." + nm.right(16);
                                }

                                mainWidget->StatsBuffer[index].name = nm;
                                //     qDebug() << "k=" << k << "j=" << j << "status:" << back[i].status << "name" << nm << "totalsize" << back[i].r.totalsize << "size" << back[i].r.size;
                                //qDebug() << "name " << nm;
                                //  }

                                mainWidget->StatsBuffer[index].file = s;

                                if (back[i].r.totalsize > 0) {    // taille prédéfinie
                                    mainWidget->StatsBuffer[index].sizeTotal = back[i].r.totalsize;
                                    mainWidget->StatsBuffer[index].size = back[i].r.size;

                                } else { // pas de taille prédéfinie
                                    if (back[i].status == 0) {    // STATUS_READY
                                        mainWidget->StatsBuffer[index].sizeTotal = back[i].r.size;
                                        mainWidget->StatsBuffer[index].size = back[i].r.size;

                                    } else {
                                        mainWidget->StatsBuffer[index].sizeTotal = 8192;
                                        mainWidget->StatsBuffer[index].size = (back[i].r.size % 8192);
                                    }
                                }
                            }

                            index++;
                        }
                    }
                }
            }
        }

        mainWidget->mutex.unlock();

#ifdef MY_DEBUG

        for (int d = 0; d < index; d++) {
            if (mainWidget->StatsBuffer[d].strStatus.length() > 0) {
                qDebug() << "index=" << d <<  mainWidget->StatsBuffer[d].file <<  mainWidget->StatsBuffer[d].size;
            }
        }

#endif
        //     ((ProgressTab*)mainWidget->widgets[4])->inProcessRefresh();
        //     qDebug() << "index = " << index;


        mainWidget->SInfo.refresh = 1;
    }

    return (mainWidget->termine == 0);
}


char* next_token(char* p, int flag)
{
    int detect = 0;
    int quote = 0;
    p--;

    do {
        p++;

        if (flag && (*p == '\\')) { // sauter \x ou \"
            if (quote) {
                char c = '\0';

                if (*(p + 1) == '\\') {
                    c = '\\';
                } else if (*(p + 1) == '"') {
                    c = '"';
                }

                if (c) {
                    char* tempo = (char*)malloc(strlen(p) + 2 + 2);
                    tempo[0] = c;
                    tempo[1] = '\0';
                    strcat(tempo, p + 2);
                    strcpy(p, tempo);
                    free(tempo);
                }
            }
        } else if (*p == 34) { // guillemets (de fin)
            char* tempo = (char*)malloc(strlen(p) + 2);
            tempo[0] = '\0';
            strcat(tempo, p + 1);
            strcpy(p, tempo);  /* wipe "" */
            p--;
            /* */
            quote = !quote;
            /* */
            free(tempo);
        } else if (*p == 32) {
            if (!quote) {
                detect = 1;
            }
        } else if (*p == '\0') {
            p = NULL;
            detect = 1;
        }
    } while (!detect);

    return p;
}


void httraq_main()
{
    int r; // result

    mainWidget->termine = 0;
    mainWidget->termine_requested = 0;
    mainWidget->shell_terminated = 0;
    mainWidget->soft_term_requested = 0;

    hts_init();

    if (mainWidget->global_opt != NULL) {
        hts_free_opt(mainWidget->global_opt);
        mainWidget->global_opt = NULL;
    }

    // #ifndef _DEBUG
    //     __try
    // #endif

    mainWidget->global_opt = hts_create_opt();

    //     ASSERT(mainWidget->global_opt->size_httrackp == sizeof(httrackp))


    {
        CHAIN_FUNCTION(mainWidget->global_opt, init, wrapper_init, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, uninit,  wrapper_uninit, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, start,  wrapper_start, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, end,  wrapper_end, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, chopt,  wrapper_chopt, NULL); // change options
        CHAIN_FUNCTION(mainWidget->global_opt, preprocess, wrapper_preprocesshtml, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, postprocess, wrapper_postprocesshtml, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, check_html,  wrapper_checkhtml, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, query, wrapper_query, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, query2, wrapper_query2, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, query3, wrapper_query3, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, loop,  wrapper_loop, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, check_link,  wrapper_check, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, check_mime, wrapper_check_mime, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, pause,  wrapper_pause, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, filesave,  wrapper_filesave, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, filesave2,  wrapper_filesave2, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, linkdetected, wrapper_linkdetected, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, linkdetected2, wrapper_linkdetected2, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, xfrstatus, wrapper_xfrstatus, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, savename, wrapper_savename, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, sendhead, wrapper_sendheader, NULL);
        CHAIN_FUNCTION(mainWidget->global_opt, receivehead, wrapper_receiveheader, NULL);

        string cmdPar = mainWidget->cmdOpt.toStdString();
        //         qDebug() << mainWidget->cmdOpt;
        // couper en morceaux
        char **argv;
        int argvAlloc = 1024;
        int argc = 1;
        {
            char* p = (char*)cmdPar.c_str();
            argv = (char**) malloc(argvAlloc * sizeof(char*));
            argv[0] = (char*)"httraqt";

            do {
                if (argc >= argvAlloc) {
                    argvAlloc *= 2;
                    argv = (char**) realloc(argv, argvAlloc * sizeof(char*));

                    if (argv == NULL) {
                        break;
                    }
                }

                argv[argc++] = p;
                argv[argc] = NULL;

                p = next_token(p, 0); // prochain token

                if (p) {
                    *p = 0;  // octet nul (tableau)
                    p++;
                }
            } while (p != NULL);
        }

        r = hts_main2(argc, argv, mainWidget->global_opt);

        sleep(1);
        free(argv);
    }
    // qDebug() << "termine after hts_main2";
    mainWidget->termine = 1;

    if (mainWidget->global_opt != NULL) {
        hts_free_opt(mainWidget->global_opt);
        mainWidget->global_opt = NULL;
    }

    //     sleep(1);
    // #ifndef _DEBUG
    //     __catch(ExcFilter_(GetExceptionCode(), GetExceptionInformation()))
    //     {
    //         r = -100;
    //     }
    // #endif
    //     htsthread_wait_n(1);
    hts_uninit();
}

