#include "avrdude.h"
#include "programmer.h"
#include "part.h"
#include <string.h>
#include <stdarg.h>
#include <iostream>

extern "C" {
#if defined(__WINDOWS__)
#include "avrdude/libavrdude.h"
#else
#include "libavrdude.h"
#endif

/*
#include "avrdude/avrdude.h"
#include "avrdude/avr.h"
#include "avrdude/config.h"
#include "avrdude/confwin.h"
#include "avrdude/fileio.h"
#include "avrdude/lists.h"
#include "avrdude/par.h"
#include "avrdude/pindefs.h"
#include "avrdude/term.h"
#include "avrdude/safemode.h"
#include "avrdude/update.h"
*/

// dummy:
void crcappend() {}
void crcverify() {}

const char * version      = "1.0";
char * progname;
int    verbose;     /* verbose output */
int    ovsigck;     /* 1=override sig check, 0=don't */
int    quell_progress; /* un-verebose output */
int    do_cycles;   /* track erase-rewrite cycles */

char   progbuf[PATH_MAX]; /* temporary buffer of spaces the same
                             length as progname; used for lining up
                             multiline messages */
}

void doAvrdudeProgress(int percent, double etime, bool replace);

#if (LIBAVRDUDE_VER >= 70)
static void do_update_progress(int percent, double etime, const char *hdr, int dummy) {
#else
static void do_update_progress(int percent, double etime, char *hdr) {
#endif
  doAvrdudeProgress(percent, etime, false);
}


Avrdude::Avrdude(const std::string & appName, const std::string & configFile) {
    std::cout << "DBG: Avrdude::Avrdude" << std::endl;
#if (LIBAVRDUDE_VER >= 73)
  ::init_cx(NULL);
#endif
  ::verbose = 5;
  ::quell_progress = 0;
  ::strcpy(progbuf, appName.c_str());
  progname = progbuf;
  std::cout << "DBG: Avrdude::Avrdude 1" << std::endl;
  ::init_config();
  std::cout << "DBG: Avrdude::Avrdude 2" << std::endl;
  std::cout << configFile << std::endl;
  ::read_config(configFile.c_str());
  //::read_config("dummy.conf");
  std::cout << "DBG: Avrdude::Avrdude END" << std::endl;
  ::update_progress = do_update_progress;
}

Avrdude::~Avrdude() {
}

Programmer * Avrdude::locateProgrammer(const std::string & name) {
  return Programmer::locateProgrammer(name);
}

Part * Avrdude::locatePart(const std::string & name) {
  return Part::locatePart(name);
}

void doAvrdudeMessage(int type, const char * msg);

extern "C" {
    /* WORKAROUND BEGIN */
    typedef struct {                // Value of -1 typically means unknown
        const char *name;             // Name of part
        uint16_t mcuid;               // ID of MCU in 0..2039
        uint8_t  avrarch;             // F_AVR8L, F_AVR8, F_XMEGA or F_AVR8X
        uint8_t sigs[3];              // Signature bytes
        int32_t flashoffset;          // Flash offset
        int32_t flashsize;            // Flash size
        int16_t pagesize;             // Flash page size
        int8_t  nboots;               // Number of supported boot sectors
        int16_t bootsize;             // Size of (smallest) boot sector
        int32_t eepromoffset;         // EEPROM offset
        int32_t eepromsize;           // EEPROM size
        int32_t eeprompagesize;       // EEPROM page size
        int32_t sramstart;            // SRAM offset
        int32_t sramsize;             // SRAM size
        int8_t  nfuses;               // Number of fuse bytes
        int8_t  nlocks;               // Number of lock bytes
        uint8_t ninterrupts;          // Number of vectors in interrupt vector table
        const char * const *isrtable; // Interrupt vector table vector names
    } uPcore_t;
    
    extern const uPcore_t uP_table[0];
    
    const char *partdesc;
    const uPcore_t uP_table[] = {};
    /* WORKAROUND END */
    
    int avrdude_message(const int msglvl, const char *format, ...) {
        std::cout << "DBG: avrdude_message" << std::endl;
        char msg[4096];
        va_list aptr;
        va_start(aptr, format);
        vsnprintf(msg, sizeof(msg), format, aptr);
        va_end(aptr);
        doAvrdudeMessage(msglvl, msg);
        return 0;
    }

#if (LIBAVRDUDE_VER >= 70)
    int avrdude_message2(FILE *fp, int lno, const char *file, const char *func, int msgmode, int msglvl, const char *format, ...) {
        std::cout << "DBG: avrdude_message2" << std::endl;
        
        int rc = 0;
        va_list ap;
        return 0;
    }
#endif

}
