/**********************************************************************************************
    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 "CProtocol.h"
#include "CWptDB.h"
#include "CWpt.h"
#include "CTrackDB.h"
#include "CTrack.h"
#include "CCanvas.h"

#include <QTcpSocket>
#include <QtGui>

CProtocol::CProtocol(QTcpSocket * socket)
: QObject(socket)
, socket(socket)
, timeout(3000)
{
    qDebug() << "CProtocol::CProtocol(QTcpSocket * socket)";

    connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
}


CProtocol::~CProtocol()
{
    qDebug() << "CProtocol::~CProtocol()";
}


void CProtocol::send(const packet_e type, const QByteArray& data)
{
    QByteArray packet;
    QDataStream out(&packet,QIODevice::WriteOnly);
    out << (qint32)type;
    out << (qint32)0;
    out << data;
    out.device()->seek(sizeof(type));
    out << (qint32)(packet.size() - 2 * sizeof(qint32));

    socket->write(packet);
}


bool CProtocol::recv(packet_e& type, QByteArray& data)
{
    qint32 size;
    QDataStream in(socket);

    while(socket->bytesAvailable() < (int)(2 * sizeof(qint32))) {
        if (!socket->waitForReadyRead(timeout)) {
            return false;
        }
    }

    in >> (qint32&)type;
    in >> size;

    while(socket->bytesAvailable() < size) {
        if (!socket->waitForReadyRead(timeout)) {
            return false;
        }
    }

    in >> data;
    return true;
}

void CProtocol::slotReadyRead()
{
    packet_e type;
    QByteArray data;

    if(!recv(type,data)) {
        send(eError,tr("Incomming packet timed out.").toUtf8());
        return;
    }
    emit sigType(type);
    QDataStream stream(&data, QIODevice::ReadWrite);

    if(type == eC2HWpt){
        QString errmsg;
        CWpt wpt;
        stream >> wpt;
        emit sigStatus(wpt.name);
        data.clear();

        if(!CWptDB::self().add(wpt, errmsg)){
            send(eError,(tr("Failed to add waypoint to database. ") + errmsg).toUtf8());
            qDebug() << "yyyyyyyyyyyyyyy" << errmsg;
        }
        else{
            send(eAck,data);
            emit sigStatus(wpt.name  + tr(" - done"));
        }
    }
    else if(type == eH2CWptQuery){
        data.clear();
        stream.device()->seek(0);

        QStringList keys, names, icons;
        QString errmsg;

        if(!CWptDB::self().list(keys, names, icons, errmsg)){
            send(eError,(tr("Failed to query database. ") + errmsg).toUtf8());
        }
        else{
            emit sigStatus(tr("send waypoint list"));
            stream << keys.count();
            for(int i = 0; i < keys.count(); ++i){
                stream << keys[i] << names[i];
            }

            stream << "" << "";
            send(eAck,data);
            emit sigStatus(tr("send waypoint list"));
        }
    }
    else if(type == eH2CWpt){
        QString errmsg;
        QString key;
        stream >> key;

        CWpt wpt;
        if(!CWptDB::self().get(key,wpt, errmsg)){
            send(eError,(tr("Failed to query database. ") + errmsg).toUtf8());
        }
        else{
            data.clear();
            stream.device()->seek(0);

            emit sigStatus(wpt.name);
            stream << wpt;

            send(eAck,data);
            emit sigStatus(wpt.name);
        }
    }
    else if(type == eH2CTrkQuery){
        data.clear();
        stream.device()->seek(0);

        QStringList keys, names, distance;
        QString errmsg;

        if(!CTrackDB::self().list(keys, names, distance, errmsg)){
            send(eError,(tr("Failed to query database. ") + errmsg).toUtf8());
        }
        else{
            emit sigStatus(tr("send track list"));
            stream << keys.count();
            for(int i = 0; i < keys.count(); ++i){
                stream << keys[i] << names[i];
            }

            stream << "" << "";
            send(eAck,data);
            emit sigStatus(tr("send track list"));
        }
    }
    else if(type == eH2CTrk){
        QString errmsg;
        QString key;
        stream >> key;

        CTrack trk;
        if(!CTrackDB::self().get(key, trk, errmsg)){
            send(eError,(tr("Failed to query database. ") + errmsg).toUtf8());
        }
        else{
            data.clear();
            stream.device()->seek(0);

            emit sigStatus(trk.name);
            stream << trk;

            send(eAck,data);
            emit sigStatus(trk.name);
        }
    }
    else if(type == eC2HTrk){
        QString errmsg;
        CTrack trk;
        stream >> trk;
        emit sigStatus(trk.name);
        data.clear();

        if(!CTrackDB::self().add(trk, errmsg)){
            send(eError,(tr("Failed to add track to database. ") + errmsg).toUtf8());
        }
        else{
            send(eAck,data);
            emit sigStatus(trk.name  + tr(" - done"));
        }
    }
    else if(type == eH2CScreen){
        CCanvas::self().getDlgTransfer().hide();
        qApp->processEvents();
        QPixmap screenshot = QPixmap::grabWindow(QApplication::desktop()->winId());

        data.clear();

        if(!screenshot.isNull()){
            stream << screenshot.toImage();
            send(eAck,data);
        }
        else{
            send(eError,tr("Failed to aquire screenshot.").toUtf8());
        }
    }
    else{
        send(eError,tr("Packet unknown").toUtf8());
    }
}
