/**********************************************************************************************
    Copyright (C) 2014 Oliver Eichler <oliver.eichler@gmx.de>

    This program 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.

    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 General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

**********************************************************************************************/

#include "CQlgtTrack.h"

#include <QtWidgets>

#include "CMainWindow.h"

QDataStream& operator>>(QDataStream& s, CFlags& flag) {
  quint32 f;
  s >> f;
  flag.setFlags(f);
  flag.setChanged(true);
  return s;
}

QDataStream& operator<<(QDataStream& s, CFlags& flag) {
  s << flag.flag();
  return s;
}

struct trk_head_entry_t {
  trk_head_entry_t() : type(CQlgtTrack::eEnd), offset(0) {}
  qint32 type;
  quint32 offset;
  QByteArray data;
};

QDataStream& operator>>(QDataStream& s, CQlgtTrack& track) {
  quint32 nTrkPts = 0;
  QIODevice* dev = s.device();
  qint64 pos = dev->pos();

  char magic[9];
  s.readRawData(magic, 9);

  if (strncmp(magic, "QLTrk   ", 9)) {
    dev->seek(pos);
    return s;
  }

  QList<trk_head_entry_t> entries;

  while (1) {
    trk_head_entry_t entry;
    s >> entry.type >> entry.offset;
    entries << entry;
    if (entry.type == CQlgtTrack::eEnd) {
      break;
    }
  }

  QList<trk_head_entry_t>::iterator entry = entries.begin();
  while (entry != entries.end()) {
    qint64 o = pos + entry->offset;
    dev->seek(o);
    s >> entry->data;

    switch (entry->type) {
      case CQlgtTrack::eBase: {
        QDataStream s1(&entry->data, QIODevice::ReadOnly);
        s1.setVersion(QDataStream::Qt_4_5);

        s1 >> track.key;
        s1 >> track.timestamp;
        s1 >> track.name;
        s1 >> track.comment;
        s1 >> track.colorIdx;
        s1 >> track.parentWpt;
        if (!s1.atEnd()) {
          s1 >> track.doScaleWpt2Track;
        }
        if (!s1.atEnd()) {
          s1 >> track.cntMedianFilterApplied;
        }
        if (!s1.atEnd()) {
          s1 >> track.useMultiColor;
        }
        if (!s1.atEnd()) {
          s1 >> track.idMultiColor;
        }

        // track.setColor(track.colorIdx);

        break;
      }

      case CQlgtTrack::eTrkPts: {
        QDataStream s1(&entry->data, QIODevice::ReadOnly);
        s1.setVersion(QDataStream::Qt_4_5);
        quint32 n;

        track.track.clear();
        s1 >> nTrkPts;

        for (n = 0; n < nTrkPts; ++n) {
          CQlgtTrack::pt_t trkpt;
          s1 >> trkpt.lon;
          s1 >> trkpt.lat;
          s1 >> trkpt.ele;
          s1 >> trkpt.timestamp;
          s1 >> trkpt.flags;

          trkpt._lon = trkpt.lon;
          trkpt._lat = trkpt.lat;
          trkpt._ele = trkpt.ele;
          trkpt._timestamp = trkpt.timestamp;
          trkpt._timestamp_msec = trkpt.timestamp_msec;

          track << trkpt;
        }
        break;
      }

      case CQlgtTrack::eTrkPts2: {
        QDataStream s1(&entry->data, QIODevice::ReadOnly);
        s1.setVersion(QDataStream::Qt_4_5);

        quint32 nTrkPts1 = 0;

        s1 >> nTrkPts1;
        if (nTrkPts1 != nTrkPts) {
          QMessageBox::warning(
              CMainWindow::getBestWidgetForParent(), CQlgtTrack::tr("Corrupt track ..."),
              CQlgtTrack::tr("Number of trackpoints is not equal the number of training data trackpoints."),
              QMessageBox::Ignore, QMessageBox::Ignore);
          break;
        }

        QList<CQlgtTrack::pt_t>::iterator pt1 = track.track.begin();
        while (pt1 != track.track.end()) {
          quint32 dummy;
          s1 >> pt1->timestamp_msec;
          s1 >> dummy;
          s1 >> dummy;
          s1 >> dummy;
          s1 >> dummy;
          s1 >> dummy;

          ++pt1;
        }
        break;
      }

        //            case CQlgtTrack::eTrain:
        //            {
        //                QDataStream s1(&entry->data, QIODevice::ReadOnly);
        //                s1.setVersion(QDataStream::Qt_4_5);

        //                quint32 nTrkPts1 = 0;

        //                s1 >> nTrkPts1;
        //                if(nTrkPts1 != nTrkPts)
        //                {
        //                    QMessageBox::warning(0, tr("Corrupt track ..."), tr("Number of trackpoints is not equal
        //                    the number of training data trackpoints."), QMessageBox::Ignore,QMessageBox::Ignore);
        //                    break;
        //                }

        //                QList<CQlgtTrack::pt_t>::iterator pt1 = track.track.begin();
        //                while (pt1 != track.track.end())
        //                {
        //                    s1 >> pt1->heartReateBpm;
        //                    s1 >> pt1->cadenceRpm;
        //                    pt1++;
        //                }

        //                track.setTraineeData();
        //                break;
        //            }
      case CQlgtTrack::eTrkExt1: {
        QDataStream s1(&entry->data, QIODevice::ReadOnly);
        s1.setVersion(QDataStream::Qt_4_5);
        quint32 nTrkPts1 = 0;

        s1 >> nTrkPts1;
        if (nTrkPts1 != nTrkPts) {
          QMessageBox::warning(
              CMainWindow::getBestWidgetForParent(), CQlgtTrack::tr("Corrupt track ..."),
              CQlgtTrack::tr("Number of trackpoints is not equal the number of extended data trackpoints."),
              QMessageBox::Ignore, QMessageBox::Ignore);
          break;
        }

        QList<CQlgtTrack::pt_t>::iterator pt1 = track.track.begin();
        while (pt1 != track.track.end()) {
          ///< [m]
          s1 >> pt1->altitude;
          ///< [m]
          s1 >> pt1->height;
          ///< [m/s]
          s1 >> pt1->velocity;
          ///< [deg]
          s1 >> pt1->heading;
          ///< [deg]
          s1 >> pt1->magnetic;
          s1 >> pt1->vdop;
          s1 >> pt1->hdop;
          s1 >> pt1->pdop;
          s1 >> pt1->x;  ///< [m] cartesian gps coordinate
          s1 >> pt1->y;  ///< [m] cartesian gps coordinate
          s1 >> pt1->z;  ///< [m] cartesian gps coordinate
          ///< [m/s] velocity
          s1 >> pt1->vx;
          ///< [m/s] velocity
          s1 >> pt1->vy;
          ///< [m/s] velocity
          s1 >> pt1->vz;
          ++pt1;
        }

        track.setExt1Data();
        break;
      }

      case CQlgtTrack::eTrkShdw: {
        QDataStream s1(&entry->data, QIODevice::ReadOnly);
        s1.setVersion(QDataStream::Qt_4_5);
        quint32 n;

        quint32 nTrkPts1 = 0;

        s1 >> nTrkPts1;
        if (nTrkPts1 != nTrkPts) {
          QMessageBox::warning(
              CMainWindow::getBestWidgetForParent(), CQlgtTrack::tr("Corrupt track ..."),
              CQlgtTrack::tr("Number of trackpoints is not equal the number of shadow data trackpoints."),
              QMessageBox::Ignore, QMessageBox::Ignore);
          break;
        }

        for (n = 0; n < nTrkPts; ++n) {
          CQlgtTrack::pt_t& trkpt = track.track[n];
          s1 >> trkpt._lon;
          s1 >> trkpt._lat;
          s1 >> trkpt._ele;
        }
        track.hasShadow1 = true;
        break;
      }

      case CQlgtTrack::eTrkShdw2: {
        QDataStream s1(&entry->data, QIODevice::ReadOnly);
        s1.setVersion(QDataStream::Qt_4_5);
        quint32 n;

        quint32 nTrkPts1 = 0;

        s1 >> nTrkPts1;
        if (nTrkPts1 != nTrkPts) {
          QMessageBox::warning(
              CMainWindow::getBestWidgetForParent(), CQlgtTrack::tr("Corrupt track ..."),
              CQlgtTrack::tr("Number of trackpoints is not equal the number of shadow data trackpoints."),
              QMessageBox::Ignore, QMessageBox::Ignore);
          break;
        }

        for (n = 0; n < nTrkPts; ++n) {
          quint32 dummy;
          CQlgtTrack::pt_t& trkpt = track.track[n];
          s1 >> trkpt._timestamp;
          s1 >> trkpt._timestamp_msec;
          s1 >> dummy;
          s1 >> dummy;
          s1 >> dummy;
          s1 >> dummy;
          s1 >> dummy;
        }
        track.hasShadow2 = true;
        break;
      }

      default:;
    }

    ++entry;
  }

  return s;
}

QDataStream& operator<<(QDataStream& s, CQlgtTrack& trk) { return s; }

CQlgtTrack::CQlgtTrack(quint64 id, QObject* parent)
    : QObject(parent), IItem(id), ext1Data(false), hasShadow1(false), hasShadow2(false) {}

CQlgtTrack::~CQlgtTrack() {}

CQlgtTrack& CQlgtTrack::operator<<(const pt_t& pt) {
  track.push_back(pt);
  track.last().idx = track.size() - 1;
  track.last().flags &= ~pt_t::eCursor;
  track.last().flags &= ~pt_t::eFocus;
  track.last().flags &= ~pt_t::eSelected;

  return *this;
}
