/**********************************************************************************************
    Copyright (C) 2008 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 2 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, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA

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

#include "CTrack.h"
#include "CTrackDB.h"
#include "CCanvas.h"
#include "CMapDB.h"
#include "IMap.h"
#include <QtGui>
#include <proj_api.h>



STrackPoint trackbuffer[CHUNKSIZE];
quint32     trackIdx = 0;
STrackPoint trackbuffer1[CHUNKSIZE];
quint32     trackIdx1 = 0;

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


QDataStream& operator <<(QDataStream& s, CTrack& track)
{
    QList<trk_head_entry_t> entries;

    //---------------------------------------
    // prepare base data
    //---------------------------------------
    trk_head_entry_t entryBase;
    entryBase.type = CTrack::eBase;
    QDataStream s1(&entryBase.data, QIODevice::WriteOnly);

    s1 << track.key();
    s1 << track.timestamp;
    s1 << track.name;
    s1 << track.comment;
    s1 << track.colorIdx;

    entries << entryBase;

    //---------------------------------------
    // prepare trackpoint data
    //---------------------------------------
    if(track.trkpts.count()){
        trk_head_entry_t entryTrkPts;
        entryTrkPts.type = CTrack::eTrkPts;
        QDataStream s(&entryTrkPts.data, QIODevice::WriteOnly);

        quint32 size = track.trkpts.count();
        s << size;

        QVector<STrackPoint>& pts = track.trkpts;
        STrackPoint pt;
        foreach(pt, pts){
            s << (float)(pt.lon * RAD_TO_DEG);
            s << (float)(pt.lat * RAD_TO_DEG);
            s << pt.ele;
            s << pt.timestamp;
            s << pt.flags;

//             qDebug() << pt.lon << pt.lat << pt.ele << pt.timestamp << pt.flags;
        }

        entries << entryTrkPts;
    }
    //---------------------------------------
    // prepare extended trackpoint data 1
    //---------------------------------------
// //     if(track.fileTrkExt1.exists()){
// //         trk_head_entry_t entryTrkExt1;
// //         entryTrkExt1.type = CTrack::eTrkExt1;
// //         QDataStream s(&entryTrkExt1.data, QIODevice::WriteOnly);
// //
// //         track.fileTrkExt1.open(QIODevice::ReadOnly);
// //         quint32 size = track.fileTrkExt1.size() / sizeof(STrackExt1);
// //         s << size;
// //
// //         QByteArray data = track.fileTrkExt1.readAll();
// //         s.writeRawData(data, data.size());
// //         track.fileTrkExt1.close();
// //
// //         entries << entryTrkExt1;
// //     }

    //---------------------------------------
    // prepare terminator
    //---------------------------------------
    trk_head_entry_t entryEnd;
    entryEnd.type = CTrack::eEnd;
    entries << entryEnd;

    //---------------------------------------
    //---------------------------------------
    // now start to actually write data;
    //---------------------------------------
    //---------------------------------------
    // write magic key
    s.writeRawData("QLTrk   ",9);

    // calculate offset table
    quint32 offset = entries.count() * 8 + 9;

    QList<trk_head_entry_t>::iterator entry = entries.begin();
    while(entry != entries.end()) {
        entry->offset = offset;
        offset += entry->data.size() + sizeof(quint32);
        ++entry;
    }

    // write offset table
    entry = entries.begin();
    while(entry != entries.end()) {
        s << entry->type << entry->offset;
        ++entry;
    }

    // write entry data
    entry = entries.begin();
    while(entry != entries.end()) {
        s << entry->data;
        ++entry;
    }

    return s;
}

QDataStream& operator >>(QDataStream& s, CTrack& track)
{
    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 == CTrack::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 CTrack::eBase:
            {
                QDataStream s1(&entry->data, QIODevice::ReadOnly);

                s1 >> track._key_;
                s1 >> track.timestamp;
                s1 >> track.name;
                s1 >> track.comment;
                s1 >> track.colorIdx;

                break;

            }
            case CTrack::eTrkPts:
            {
                quint32 nTrkPts,n;
                QDataStream s1(&entry->data, QIODevice::ReadOnly);
                s1 >> nTrkPts;

                STrackPoint trkpt;

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

                    trkpt.lon *= DEG_TO_RAD;
                    trkpt.lat *= DEG_TO_RAD;

                    track << trkpt;
                }
                break;
            }
            default:;
        }

        ++entry;
    }
    return s;
}

void operator >>(QFile& f, CTrack& track)
{
    f.open(QIODevice::ReadOnly);
    QDataStream s(&f);
    s >> track;
    f.close();
}

void operator <<(QFile& f, CTrack& track)
{
    f.open(QIODevice::WriteOnly);
    QDataStream s(&f);
    s << track;
    f.close();
}


CTrack::CTrack()
: colorIdx(4)
{

}


CTrack::~CTrack()
{

}

void CTrack::genKey()
{
    _key_ = QString("%1%2").arg(timestamp).arg(name);
}

const QString& CTrack::key()
{
    if(_key_.isEmpty()) genKey();
    return _key_;
}

void CTrack::operator <<(STrackPoint& trkpt)
{
    trkpts << trkpt;
}

void CTrack::operator <<(STrackExt1& trkpt)
{
    trkext1 << trkpt;
}

const QColor CTrack::lineColors[] =
{
    Qt::black                    // 0
    ,Qt::darkRed                 // 1
    ,Qt::darkGreen               // 2
    ,Qt::darkYellow              // 3
    ,Qt::darkBlue                // 4
    ,Qt::darkMagenta             // 5
    ,Qt::darkCyan                // 6
    ,Qt::gray                    // 7
    ,Qt::darkGray                // 8
    ,Qt::red                     // 9
    ,Qt::green                   // 10
    ,Qt::yellow                  // 11
    ,Qt::blue                    // 12
    ,Qt::magenta                 // 13
    ,Qt::cyan                    // 14
    ,Qt::white                   // 15
    ,Qt::transparent             // 16
};
