#include "config.h"
#include <QDebug>
#include <QFile>
#include <cstring>
#include <catch2/catch_test_macros.hpp>

using namespace std;

// make test ARGS="-V -I 3,3"

struct ZipLocalFileHeader
{
  quint32 header_signature;
  char version[2];
  char bit_flag[2];
  char compression_method[2];
  char last_modification_time[2];
  char last_modification_date[2];
  char crc[4];
  quint32 compressed_size    = 0;
  quint32 uncompressed_size  = 0;
  quint16 name_length        = 0;
  quint16 extra_field_length = 0;
};


/** @brief function that reads the device to find the next zip header file and
 * tell if it is the expected filename
 *
 * it reads the device to find the header describing a file contained in the zip
 * archive once the header is found, it checks that this is the expected
 * filename
 *
 * @param look_for a file name that this archive must contain
 *
 * @return bool If the filename zip header is equal to "look_for", then it
 * returns true, false otherwise
 */
bool
readZipHeaderBuffer(QIODevice *p_device, const QString &look_for)
{
  QString filename;


  ZipLocalFileHeader zip_header;
  qDebug();
  char zip_header_buffer[30];
  if(p_device->atEnd())
    {
      qDebug();
      return false;
    }
  p_device->read(zip_header_buffer, sizeof(char[30]));
  qDebug();
  if(p_device->atEnd())
    {
      qDebug() << "atEnd 1";
      return false;
    }

  std::strncpy(zip_header.crc, zip_header_buffer + 14, 4);
  zip_header.header_signature   = *(zip_header_buffer);
  zip_header.compressed_size    = *(zip_header_buffer + 18);
  zip_header.uncompressed_size  = *(zip_header_buffer + 22);
  zip_header.name_length        = *(zip_header_buffer + 26);
  zip_header.extra_field_length = *(zip_header_buffer + 28);


  char word[255];
  std::strncpy(word, zip_header.crc, 4);
  word[4] = '\0';
  qDebug() << "word=" << word;

  qDebug() << "header_signature=" << zip_header.header_signature;
  qDebug() << "filename length=" << zip_header.name_length;
  qDebug() << "compressed size=" << zip_header.compressed_size;
  qDebug() << "uncompressed size=" << zip_header.uncompressed_size;
  qDebug();

  char one_byte;
  quint16 i = 0;
  while(i < zip_header.name_length)
    {
      p_device->read(&one_byte, sizeof(char));

      if(p_device->atEnd())
        {
          qDebug() << "atEnd 4";
          return false;
        }
      if(i < 254)
        {
          word[i] = one_byte;
        }
      else
        {
          word[254] = '\0';
        }

      i++;
    }
  if(i < 254)
    {
      word[i] = '\0';
    }


  filename = word;
  qDebug() << "filename=" << filename;
  qDebug();
  p_device->read(word, sizeof(char[zip_header.extra_field_length]));

  if(p_device->atEnd())
    {
      qDebug() << "atEnd 3";
      return false;
    }

  qDebug();
  i = 0;
  while(i < zip_header.extra_field_length)
    {
      p_device->read(&one_byte, sizeof(char));

      if(p_device->atEnd())
        {
          qDebug() << "atEnd 4";
          return false;
        }

      i++;
    }
  qDebug();
  if(look_for == filename)
    return true;
  qDebug();
  quint32 j = 0;
  while(j < zip_header.compressed_size)
    {
      p_device->read(&one_byte, sizeof(char));

      if(p_device->atEnd())
        {
          qDebug() << "atEnd 5";
          return false;
        }

      j++;
    }
  return false;
}


TEST_CASE("test zlib compliance.", "[zlib]")
{
  // Set the debugging message formatting pattern.
  qSetMessagePattern(QString("%{file}@%{line}, %{function}(): %{message}"));

  SECTION("..:: test zlib compliance on an ODS file from data tests ::..",
          "[zlib]")
  {
    QFile file(QString(CMAKE_SOURCE_DIR).append("/test/data/xic.ods"));

    if(file.open(QIODevice::ReadOnly))
      {
        INFO(QString("reading file %1").arg(file.fileName()).toStdString());
        // if(!file.open(QIODevice::ReadOnly))
        //   qFatal(QString("Failed to open file %1").arg(file.fileName()));


        while(readZipHeaderBuffer(&file, "content") == false)
          {
            if(file.atEnd())
              {
                qDebug() << "atEnd main";
                break;
              }
            qDebug() << "ok main";
          }
        file.close();
      }
    else
      {
        FAIL("Unable to read file" << file.fileName().toStdString());
      }
  }
}
