/***************************************************************************
 * C++ Implementation:                                                     *
 * Copyright (C) 2012-2014 by Eduard Kalinowski                            *
 * eduard_kalinowski@yahoo.de                                              *
 *                                                                         *
 * HTTraQt is free software; you can redistribute it and/or                *
 * modify it under the terms of the GNU Lesser General Public              *
 * License as published by the Free Software Foundation; either            *
 * version 3 of the License, or (at your option) any later version.        *
 *                                                                         *
 * HTTraQt 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 Lesser 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    *
 ***************************************************************************/


#ifndef HTINTERFACE_H
#define HTINTERFACE_H


#ifdef __cplusplus
extern "C" {
#endif

#include <htsglobal.h>
#include <htsopt.h>
// #include <htslib.h>
#include <httrack-library.h>
#include <htsnet.h>
#include <htswrap.h>
// #include <htscore.h>


typedef struct {
    int active;
    char name[1024];
    int port;
    char bindhost[256];   // bind this host
} htsrequest_proxy;


#ifndef HTS_DEF_FWSTRUCT_htsrequest
#define HTS_DEF_FWSTRUCT_htsrequest
typedef struct htsrequest htsrequest;
#endif
struct htsrequest {
    short int user_agent_send;    // user agent (ex: httrack/1.0 [sun])
    short int http11;             // l'en tête peut (doit) être signé HTTP/1.1 et non HTTP/1.0
    short int nokeepalive;        // pas de keep-alive
    short int range_used;         // Range utilisé
    short int nocompression;      // Pas de compression
    short int flush_garbage;      // recycled
    char user_agent[128];
    char referer[256];
    char from[256];
    char lang_iso[64];
    htsrequest_proxy proxy;       // proxy
};


// structure pour retour d'une connexion/prise d'en tête
#ifndef HTS_DEF_FWSTRUCT_htsblk
#define HTS_DEF_FWSTRUCT_htsblk
typedef struct htsblk htsblk;
#endif
struct htsblk {
    int statuscode;        // status-code, -1=erreur, 200=OK,201=..etc (cf RFC1945)
    short int notmodified; // page ou fichier NON modifié (transféré)
    short int is_write;    // sortie sur disque (out) ou en mémoire (adr)
    short int is_chunk;    // mode chunk
    short int compressed;  // compressé?
    short int empty;       // vide?
    short int keep_alive;  // Keep-Alive?
    short int keep_alive_trailers;  // ..with trailers extension
    int keep_alive_t;      // KA timeout
    int keep_alive_max;    // KA number of requests
    char* adr;             // adresse du bloc de mémoire, NULL=vide
    char* headers;         // adresse des en têtes si présents
    FILE* out;             // écriture directe sur disque (si is_write=1)
    LLint size;            // taille fichier
    char msg[80];          // message éventuel si échec ("\0"=non précisé)
    char contenttype[64];  // content-type ("text/html" par exemple)
    char charset[64];      // charset ("iso-8859-1" par exemple)
    char contentencoding[64];  // content-encoding ("gzip" par exemple)
    char* location;        // on copie dedans éventuellement la véritable 'location'
    LLint totalsize;       // taille totale à télécharger (-1=inconnue)
    short int is_file;     // ce n'est pas une socket mais un descripteur de fichier si 1
    T_SOC soc;             // ID socket
    SOCaddr address;       // IP address
    int     address_size;  // IP address structure length
    FILE* fp;              // fichier pour file://
#if HTS_USEOPENSSL
    short int ssl;         // is this connection a SSL one? (https)
    // BIO* ssl_soc;          // SSL structure
    SSL * ssl_con;         // connection structure
#endif
    char lastmodified[64]; // Last-Modified
    char etag[64];         // Etag
    char cdispo[256];      // Content-Disposition coupé
    LLint  crange;         // Content-Range
    int debugid;           // debug connection
    /* */
    htsrequest req;        // paramètres pour la requête
    /*char digest[32+2];   // digest md5 généré par le moteur ("" si non généré)*/
};




// chargement de fichiers en 'arrière plan'
#ifndef HTS_DEF_FWSTRUCT_lien_back
#define HTS_DEF_FWSTRUCT_lien_back
typedef struct lien_back lien_back;
#endif

struct lien_back {
#if DEBUG_CHECKINT
    char magic;
#endif
    char url_adr[HTS_URLMAXSIZE * 2];   // adresse
    char url_fil[HTS_URLMAXSIZE * 2];   // nom du fichier distant
    char url_sav[HTS_URLMAXSIZE * 2];   // nom à sauver sur disque (avec chemin éventuel)
    char referer_adr[HTS_URLMAXSIZE * 2]; // adresse host page referer
    char referer_fil[HTS_URLMAXSIZE * 2]; // fichier page referer
    char location_buffer[HTS_URLMAXSIZE * 2]; // "location" en cas de "moved" (302,..)
    char* tmpfile;                           // nom à sauver temporairement (compressé)
    char tmpfile_buffer[HTS_URLMAXSIZE * 2]; // buffer pour le nom à sauver temporairement
    char send_too[1024];    // données à envoyer en même temps que le header
    int status;             // status (-1=non utilisé, 0: prêt, >0: opération en cours)
    int locked;             // locked (to be used soon)
    int testmode;           // mode de test
    int timeout;            // gérer des timeouts? (!=0  : nombre de secondes)
    TStamp timeout_refresh; // si oui, time refresh
    int rateout;            // timeout refresh? (!=0 : taux minimum toléré en octets/s)
    TStamp rateout_time;    // si oui, date de départ
    LLint maxfile_nonhtml;  // taille max d'un fichier non html
    LLint maxfile_html;     // idem pour un ficheir html
    htsblk r;               // structure htsblk de chaque objet en background
    int is_update;          // mode update
    int head_request;       // requète HEAD?
    LLint range_req_size;   // range utilisé
    TStamp ka_time_start;   // refresh time for KA
    //
    int http11;             // L'en tête doit être signé HTTP/1.1 et non HTTP/1.0
    int is_chunk;           // chunk?
    char* chunk_adr;        // adresse chunk en cours de chargement
    LLint chunk_size;       // taille chunk en cours de chargement
    LLint chunk_blocksize;  // taille data declaree par le chunk
    LLint compressed_size;  // taille compressés (stats uniquement)
    //
    //int links_index;        // to access liens[links_index]
    //
    char info[256];         // éventuel status pour le ftp
    int stop_ftp;           // flag stop pour ftp
    int finalized;          // finalized (optim memory)
    int early_add;          // was added before link heap saw it
#if DEBUG_CHECKINT
    char magic2;
#endif
};


#include <htsdefines.h>

#ifdef __cplusplus
}
#endif

// #ifndef DEBUG
// #define ASSERT(x)
// #else
#define ASSERT(x) \
    if (! (x) && !(x-1)) { \
        qDebug() << "ERROR!! Assert " << #x << " failed\n"; \
        qDebug() << " on line " << __LINE__  << "\n"; \
        qDebug() << " in file " << __FILE__ << "\n";  \
        return 1; \
    }

#ifdef _DEBUG

#define VERIFY_ISWRITEPOINTER(a) \
    { if(::IsBadWritePtr(a, sizeof(LPDWORD))) \
        { ::OutputDebugString(_T("Parameter ") _T(#a) \
                              _T(" is not a valid write pointer\r\n"));}}
#define VERIFY_ISREADPOINTER(a) \
    { if(::IsBadReadPtr(a, sizeof(LPDWORD)))\
        { ::OutputDebugString(_T("Parameter ") _T(#a) \
                              _T(" is not a valid read pointer\r\n"));}}

#define VERIFY_ISWRITEDATA(a, l)\
    { if(::IsBadWritePtr(a, l)) \
        { ::OutputDebugString(_T("Parameter ") _T(#a) \
                              _T(" is not a valid write area\r\n"));}}
#define VERIFY_ISREADDATA(a, l)\
    { if(::IsBadReadPtr(a, l))  \
        { ::OutputDebugString(_T("Parameter ") _T(#a) \
                              _T(" is not a valid read area\r\n"));}}

#define ASSERT_ISWRITEPOINTER(a)\
    { if(::IsBadWritePtr(a, sizeof(LPDWORD))) \
        { ::OutputDebugString(_T("Parameter ") _T(#a) \
                              _T(" is not a valid write pointer\r\n")); ASSERT(false);}}
#define ASSERT_ISREADPOINTER(a)\
    { if(::IsBadReadPtr(a, sizeof(LPDWORD)))  \
        { ::OutputDebugString(_T("Parameter ") _T(#a) \
                              _T(" is not a valid read pointer\r\n")); ASSERT(false);}}

#define ASSERT_ISWRITEDATA(a, l)\
    { if(::IsBadWritePtr(a, l)) \
        { ::OutputDebugString(_T("Parameter ") _T(#a) \
                              _T(" is not a valid write area\r\n")); ASSERT(false);}}
#define ASSERT_ISREADDATA(a, l)   { if(::IsBadReadPtr(a, l))  \
        { ::OutputDebugString(_T("Parameter ") _T(#a)\
                              _T(" is not a valid read area\r\n")); ASSERT(false);}}

#else

#define VERIFY_ISWRITEPOINTER(a)
#define VERIFY_ISREADPOINTER(a)

#define VERIFY_ISWRITEDATA(a, l)
#define VERIFY_ISREADDATA(a, l)

#define ASSERT_ISWRITEPOINTER(a)
#define ASSERT_ISREADPOINTER(a)

#define ASSERT_ISWRITEDATA(a, l)
#define ASSERT_ISREADDATA(a, l)

#endif



#ifdef __cplusplus
extern "C" {
#endif


#if __WIN32
#else
#define __cdecl
#endif

void httraq_main();
void htinfo_state_url(char* c);
void htinfo_mirror_info(char* c);

//     int scan_end(void);
void __cdecl wrapper_init(t_hts_callbackarg* carg);
void __cdecl wrapper_uninit(t_hts_callbackarg* carg);
int __cdecl wrapper_start(t_hts_callbackarg* carg, httrackp *opt);
int __cdecl wrapper_chopt(t_hts_callbackarg* carg, httrackp *opt);
int __cdecl wrapper_end(t_hts_callbackarg* carg, httrackp *opt);
int __cdecl wrapper_checkhtml(t_hts_callbackarg* carg, httrackp *opt, char* html, int len, char* url_adresse, char* url_fichier);
int __cdecl wrapper_preprocesshtml(t_hts_callbackarg* carg, httrackp *opt, char** html, int* len, const char* url_address, const char* url_file);
int __cdecl wrapper_postprocesshtml(t_hts_callbackarg* carg, httrackp *opt, char** html, int* len, const char* url_address, const char* url_file);
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); // appel� � chaque boucle de HTTrack
//     int __cdecl wrapper_loop ( void* _back, int back_max, int back_index, int lien_n, int lien_tot, int stat_time, hts_stat_struct* stats );
const char* __cdecl wrapper_query(t_hts_callbackarg* carg, httrackp *opt, const char* question);
const char* __cdecl wrapper_query2(t_hts_callbackarg* carg, httrackp *opt, const char* question);
const char* __cdecl wrapper_query3(t_hts_callbackarg* carg, httrackp *opt, const char* question);
int __cdecl wrapper_check(t_hts_callbackarg* carg, httrackp *opt, const char* adr, const char* fil, int status);
int __cdecl wrapper_check_mime(t_hts_callbackarg* carg, httrackp *opt, const char* adr, const char* fil, const char* mime, int status);
void __cdecl wrapper_pause(t_hts_callbackarg* carg, httrackp *opt, const char* lockfile);
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);
int __cdecl wrapper_linkdetected(t_hts_callbackarg* carg, httrackp *opt, char* link);
int __cdecl wrapper_linkdetected2(t_hts_callbackarg* carg, httrackp *opt,  char* link, const char* start_tag);
int __cdecl wrapper_xfrstatus(t_hts_callbackarg* carg, httrackp *opt, void* back);
int __cdecl wrapper_savename(t_hts_callbackarg* carg, httrackp *opt, char* adr_complete, char* fil_complete, char* referer_adr, char* referer_fil, char* save);
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);
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);
//   void htinfo_errors ( char* chaine );
//   void htinfo_active_connections ( char* chaine );
//   void htinfo_files_updated ( char* chaine );
//   void htinfo_transfer_rate ( char* chaine );
//   void htinfo_files_written ( char* chaine );
//   void htinfo_bytes_saved ( char* chaine );
//   void htinfo_time ( char* chaine );
//     void htinfo_link_detected(char* chaine);
// void htcommandend(void);


#ifdef __cplusplus
}
#endif


typedef struct {
    //     int ask_refresh;
    int refresh;
    LLint stat_bytes;
    int stat_time;
    int lien_n;
    int lien_tot;
    int stat_nsocket;
    int rate;
    int irate;
    int ft;
    LLint stat_written;
    int stat_updated;
    int stat_errors;
    int stat_warnings;
    int stat_infos;
    TStamp stat_timestart;
    int stat_back;
} t_InpInfo;


#endif