/**
 * \file pappsomspp/vendors/tims/timsframerawdatachunck.cpp
 * \date 18/6/2022
 * \author Olivier Langella
 * \brief stores raw binary tims frame
 */

/*******************************************************************************
 * Copyright (c) 2022 Olivier Langella
 *<Olivier.Langella@universite-paris-saclay.fr>.
 *
 * This file is part of the PAPPSOms++ library.
 *
 *     PAPPSOms++ is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     PAPPSOms++ 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 General Public License
 *     along with PAPPSOms++.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

#include "timsframerawdatachunck.h"
#include <QDebug>

#include "../../pappsoexception.h"

using namespace pappso;

TimsFrameRawDataChunck::TimsFrameRawDataChunck()
{
}

TimsFrameRawDataChunck::~TimsFrameRawDataChunck()
{
  if(mpa_memoryBuffer != nullptr)
    delete[] mpa_memoryBuffer;
}

bool
TimsFrameRawDataChunck::readTimsFrame(
  QFile *p_file,
  std::size_t frameId,
  const std::vector<pappso::TimsFrameRecord> &frame_record_list)
{

  m_frameId                                   = frameId;
  qint64 position                             = p_file->pos();
  const pappso::TimsFrameRecord &frame_record = frame_record_list[frameId];
  if(frameId == 1)
    {
      bool seekpos_ok = p_file->seek(frame_record.tims_offset);
      if(!seekpos_ok)
        {
          throw PappsoException(QObject::tr("ERROR reading TIMS frame %1 "
                                            "m_timsBinFile.seek(%3) failed")
                                  .arg(frameId)
                                  .arg(frame_record.tims_offset));
        }
    }
  else
    {

      if(position == (qint64)frame_record.tims_offset)
        {
          // OK
        }
      else
        {
          // need to move to frame position :
          if(position > (qint64)frame_record.tims_offset)
            {
              // get back
              p_file->seek(frame_record.tims_offset);
              position = p_file->pos();
            }
          else
            {
              const pappso::TimsFrameRecord &previous_frame_record =
                frame_record_list[frameId - 1];
              if(position < (qint64)previous_frame_record.tims_offset)
                {

                  throw PappsoException(
                    QObject::tr("ERROR reading TIMS frame %1 "
                                "file position %2 is before previous frame %3")
                      .arg(frameId)
                      .arg(position)
                      .arg(previous_frame_record.tims_offset));
                }
              else
                {
                  // catch up current position
                  qint64 move_size =
                    (qint64)frame_record.tims_offset - position;
                  p_file->read(move_size);
                  position = p_file->pos();
                }
            }
        }
    }

  if(position != (qint64)frame_record.tims_offset)
    {

      throw PappsoException(
        QObject::tr("ERROR reading TIMS frame %1 "
                    "file position %2 is different of frame offset %3")
          .arg(frameId)
          .arg(position)
          .arg(frame_record.tims_offset));
    }
  // qDebug();
  p_file->read((char *)&m_frameLength, 4);
  // frame_length = qToBigEndian(frame_length);

  // qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__
  //       << " frame_length=" << frame_length;

  // qDebug();
  p_file->read((char *)&m_frameNumberOfScans, 4);
  // scan_number = qToBigEndian(scan_number);

  // qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__
  //        << " pos=" << m_timsBinFile.pos();

  // qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__
  //       << " scan_number=" << scan_number;
  // m_timsBinFile.seek(m_indexArray.at(timsId) + 8);


  // qDebug();

  // if (m_memoryBufferSize
  if(mpa_memoryBuffer == nullptr)
    {
      qDebug() << "mpa_memoryBuffer == nullptr";
      m_memoryBufferSize = (qint64)m_frameLength + 10;
      mpa_memoryBuffer   = new char[m_memoryBufferSize];
    }
  if((m_memoryBufferSize - 10) < m_frameLength)
    {
      if(mpa_memoryBuffer != nullptr)
        {
          delete[] mpa_memoryBuffer;
        }
      m_memoryBufferSize = (qint64)m_frameLength + 10;
      mpa_memoryBuffer   = new char[m_memoryBufferSize];
    }


  // QByteArray frame_byte_array(mpa_memoryBuffer, m_memoryBufferSize);

  // qDebug();
  qint64 read_length =
    p_file->read(mpa_memoryBuffer, (qint64)m_frameLength - 8);
  // qDebug();

  // qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__
  //        << " +frame_length-1="
  //      << (quint8) * (frame_byte_array.constData() + frame_length - 1);
  // qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__
  //       << " +frame_length="
  //     << (quint8) * (frame_byte_array.constData() + frame_length);
  // m_timsBinFile.seek(m_indexArray.at(timsId) + 8);

  if(read_length + 8 != (qint64)m_frameLength)
    {
      throw PappsoException(QObject::tr("ERROR reading TIMS frame %1: "
                                        "read_length=%2 != %3frame_length")
                              .arg(frameId)
                              .arg(read_length)
                              .arg(m_frameLength));
    }

  return true;
}

char *
pappso::TimsFrameRawDataChunck::getMemoryBuffer() const
{
  return mpa_memoryBuffer;
}

quint32
pappso::TimsFrameRawDataChunck::getCompressedSize() const
{
  return m_frameLength - 8;
}

quint32
pappso::TimsFrameRawDataChunck::getFrameNumberOfScans() const
{
  return m_frameNumberOfScans;
}

quint32
pappso::TimsFrameRawDataChunck::getFrameLength() const
{
  return m_frameLength;
}

std::size_t
pappso::TimsFrameRawDataChunck::getFrameId() const
{
  return m_frameId;
}
