/*
 *
 *  Kepas - KDE Easy Publish and Share
 *
 *  Copyright (C) 2008  Tom Patzig <tpatzig@suse.de>
 *
 *  This file is part of kepas.
 *
 *  kepas 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.
 *
 *  kepas 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 kepas; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
*/

#include "receiver.h"

Receiver::Receiver(QWidget* parent)
{
	recVec = new QVector<ReceiverInfo*>;
	infoFound = 0;
	recNotify = 0;
	progress = 0;
	readall = 0;
	resolvedHost = "";
	fileCheckDone = false;
}

Receiver::~Receiver()
{
	if (recVec)
		delete recVec;

	if (infoFound != 0)
		delete infoFound;
	if (recNotify != 0)
		delete recNotify;
}


void Receiver::defReqType(QTcpSocket* sock)
{
	qDebug() << "new socket!!";
	qDebug() << "Bytes before0: " << sock->bytesAvailable();
	m_sock = sock;
	connect(m_sock,SIGNAL(readyRead()), this,SLOT(headRead()));
}

void Receiver::headRead()
{
	disconnect(m_sock,SIGNAL(readyRead()), this,SLOT(headRead()));

	QByteArray getHead;
	int i = 0;
	bool read = true;
	qDebug() << "Bytes before: " << m_sock->bytesAvailable();
	do {
		QByteArray buf;
//		int read = m_sock->readLine(buf, sizeof(buf));
		buf = m_sock->readLine(1024);
		if (buf.simplified().isEmpty())
			read = false;
		else
			getHead.append(buf);
		i++;	
		qDebug() << "lastLine: " << i;

	} while(read);

	
	QString headerString = getHead.data();
	qDebug() << "header = " << headerString;
	QHttpRequestHeader header(headerString);

	if (header.method() == "GET" && header.value("Request") == "Send") {

//		QHostInfo::lookupHost(m_sock->peerAddress().toString(),this, SLOT(hostLookedUp(QHostInfo)));

		ReceiverInfo* peerInfo = createNewPeer(header,m_sock->peerAddress().toString());
		notifyUser(peerInfo,m_sock);

	} else if (header.method() == "POST" && header.value("Request") == "Payload" ) {
		qDebug() << "Bytes: " << m_sock->bytesAvailable();
		if (checkID(header)) 
			connect(m_sock,SIGNAL(readyRead()), this,SLOT(slotReceiveData()));
	} else if (header.method() == "GET" && header.value("Request") == "GetClip") {
		notifyClipAccess(header,m_sock);
	
	} else if (header.method() == "PUT" && header.value("Request") == "SendClip") {
		notifyClipReceived(header,m_sock);

        } else if (header.method() == "PUT" && header.value("Request") == "SendNote") {
		notifyNoteReceived(header,m_sock);
	}


}

ReceiverInfo* Receiver::createNewPeer(QHttpRequestHeader& header, QString ip)
{

	info = new ReceiverInfo(header.value("Name"),"",ip,header.value("Size").toInt(),this);
//	info->hostName = resolvedHost;
//	resolvedHost = "";
	info->userName = header.value("UserName");
	
	qDebug() << "New Sender to: " << header.value("UserName") + "@" + header.value("Host");
	qDebug() << "File: " << header.value("Name") + " " + header.value("Size");

	recVec->push_back(info);
	return info;

}

void Receiver::notifyUser(ReceiverInfo* peerInfo, QTcpSocket* sock)
{
/*
	userName = header.value("UserName");
	fileName = header.value("Name");
	fileSize = header.value("Size");
*/
	float size = peerInfo->fileSize;
	QString m_size;
	if (size > (1024*1024*1024))
		m_size = QString::number(size/(1024*1024*1024)) + " GB";
	else if (size > (1024*1024))
		m_size = QString::number(size/(1024*1024)) + " MB";
	else if (size > 1024)
		m_size = QString::number(size/1024) + " KB";
	else 
		m_size = QString::number(size) + " Byte";
		
	
	m_sock = sock;	
	QString msg = QString("%1 from %2 wants to send you a file\nName : %4\nSize: %5")
				.arg(peerInfo->userName) \
//				.arg(peerInfo->hostName) \

				.arg(peerInfo->ip) \
				.arg(peerInfo->fileName) \
				.arg(m_size);

	KNotification *notification= new KNotification ( "incomingFileTransfer", 0L , KNotification::Persistent );
	notification->setText( msg );
	notification->setPixmap( QPixmap("folder-remote") );
	QStringList actions;
	actions.append(i18n( "Accept" ));
	actions.append(i18n( "Deny" ));
	notification->setActions( actions );
    
	connect(notification, SIGNAL(activated(unsigned int )), this , SLOT(slotTransferAccepted(unsigned int)));
    	
   	notification->sendEvent();
	qDebug() << "NOTIFICATION SEND!";

}

void Receiver::slotTransferAccepted(unsigned int id)
{

	qDebug() << "ID " << id;
	if (id == 1)
		sendOKToPayLoad(m_sock);
	else if (id == 2)
		sendDeny(m_sock);


}

void Receiver::notifyClipAccess(QHttpRequestHeader& header, QTcpSocket* sock)
{
/*
	QString msg = userName + " from " + hostName + " want's to see your clipboard";
	if (KMessageBox::questionYesNo(this,msg,"Clipboard Access...") == 3)
        {
                sendClipBoard(sock,header.value("SessionID"));
        }
*/
}

void Receiver::notifyClipReceived(QHttpRequestHeader& header, QTcpSocket* sock)
{
	QString userName = header.value("UserName");
	QString hostName = header.value("Host");

//	QString hostAddress = sock->peerAddress().toString();
	QByteArray clipData = sock->readAll();	

	QString clip = clipData.data();
	fullclip = clipData.data();
	if (clip.size() >= 30)
		clip.truncate(30);	

	QString msg = QString("Received Clipboard entry, from %1@%2<br/>%3<br/>Set active?")
				.arg(userName) \
				.arg(hostName) \
				.arg(clip);

        KNotification *notification= new KNotification ( "incomingFileTransfer", 0L , KNotification::Persistent );
        notification->setText( msg );
        notification->setPixmap( QPixmap("folder-remote") );
        QStringList actions;
        actions.append(i18n( "Yes" ));
        actions.append(i18n( "No" ));
        notification->setActions( actions );

        connect(notification, SIGNAL(activated(unsigned int )), this , SLOT(slotClipAccepted(unsigned int)));

        notification->sendEvent();
        qDebug() << "Notification send";
}

void Receiver::notifyNoteReceived(QHttpRequestHeader& header, QTcpSocket* sock)
{
	QString userName = header.value("UserName");
	QString hostName = header.value("Host");

	QByteArray clipData = sock->readAll();	

	fullNote = clipData.data();
        noteName = QString("%1 has left a Note at %2").arg(userName).arg(QDate::currentDate().toString());

	QString msg = QString("Received Note from %1@%2<br/>Accept?")
				.arg(userName) \
				.arg(hostName);

        KNotification *notification= new KNotification ( "incomingFileTransfer", 0L , KNotification::Persistent );
        notification->setText( msg );
        notification->setPixmap( QPixmap("folder-remote") );
        QStringList actions;
        actions.append(i18n( "Yes" ));
        actions.append(i18n( "No" ));
        notification->setActions( actions );

        connect(notification, SIGNAL(activated(unsigned int )), this , SLOT(slotNoteAccepted(unsigned int)));

        notification->sendEvent();
}

void Receiver::slotClipAccepted(unsigned int id)
{
	qDebug() << "ID " << id;
	if (id == 1)
		setClipActive(fullclip);
	fullclip = "";
	sendOKToPayLoadClip(m_sock);
}

void Receiver::slotNoteAccepted(unsigned int id)
{
	qDebug() << "ID " << id;
	if (id == 1)
		setNoteActive(noteName, fullNote);
	fullclip = "";
	sendOKToPayLoadClip(m_sock);
}

void Receiver::hostLookedUp(QHostInfo host)
{
	qDebug() << "hostname resolved: " << host.hostName();

//	if (info != NULL) {
	resolvedHost = host.hostName();
//	info->hostName = host.hostName();
//	}
}

void Receiver::sendOKToPayLoadClip(QTcpSocket* sock)
{
	qDebug() << "Sending OK to Payload Clip";

	QHttpResponseHeader resp;

	resp.setStatusLine(200,"OK to send Payload");
	resp.setValue("Date",QDate::currentDate().toString());
	resp.setValue("Content-Length","0");
	resp.setValue("Connection","close");
	
	QByteArray head;
	head.append(resp.toString().toLatin1());
	sock->write(head);
}


void Receiver::sendOKToPayLoad(QTcpSocket* sock)
{
	qDebug() << "Sending OK to Payload";

	QHttpResponseHeader resp;

	uuid = QUuid::createUuid().toString();
	info->sessionID = uuid;
	info = NULL;
	
	resp.setStatusLine(200,"OK to send Payload");
	resp.setValue("SessionID",uuid);
	resp.setValue("Date",QDate::currentDate().toString());
	resp.setValue("Content-Length","0");
	resp.setValue("Connection","close");
	
	QByteArray head;
	head.append(resp.toString().toLatin1());
	sock->write(head);
}

void Receiver::sendDeny(QTcpSocket* sock)
{
	qDebug() << "Sending Deny to Payload";

        QHttpResponseHeader resp;

        resp.setStatusLine(403,"Denied to send Payload");
        resp.setValue("Date",QDate::currentDate().toString());

        QByteArray head;
        head.append(resp.toString().toLatin1());
        sock->write(head);
	
	recVec->remove(recVec->indexOf(info));
        delete info;
        info = NULL;
}


void Receiver::sendClipBoard(QTcpSocket* sock, QString id)
{
	QHttpResponseHeader resp;

	resp.setStatusLine(200,"OK to send Payload");
	resp.setValue("SessionID",id);
	resp.setValue("Date",QDate::currentDate().toString());
	
	QByteArray head;
	head.append(resp.toString().toLatin1());
	
	dbus = new QDBusConnection("dbus");
	QDBusConnection dbusconn = dbus->connectToBus(QDBusConnection::SessionBus, "dbus");
	QString service = "org.kde.klipper";
	QString path = "/klipper";
	QString method = "getClipboardHistoryMenu";
	QString service2 = "org.kde.klipper.klipper";

	QDBusInterface* interface = new QDBusInterface(service,path,service2,dbusconn);
	QDBusReply<QStringList> reply = interface->call(method);
	
	QString list = reply.value().join("##");
	head.append(list.toLatin1());

	sock->write(head);

}

void Receiver::setClipActive(QString clipEntry)
{
	dbus = new QDBusConnection("dbus");
        QDBusConnection dbusconn = dbus->connectToBus(QDBusConnection::SessionBus, "dbus");
        QString service = "org.kde.klipper";
        QString path = "/klipper";
        QString method = "setClipboardContents";
        QString service2 = "org.kde.klipper.klipper";

        QDBusInterface* interface = new QDBusInterface(service,path,service2,dbusconn);
        QDBusReply<bool> reply = interface->call(method,clipEntry);

}

void Receiver::setNoteActive(QString name, QString noteEntry)
{
	dbus = new QDBusConnection("dbus");
        QDBusConnection dbusconn = dbus->connectToBus(QDBusConnection::SessionBus, "dbus");
        QString service = "org.kde.knotes";
        QString path = "/KNotes";
        QString method = "newNote";
        QString service2 = "org.kde.KNotes";

        QDBusInterface* interface = new QDBusInterface(service,path,service2,dbusconn);
        QDBusReply<bool> reply = interface->call(method,name,noteEntry);

}

bool Receiver::checkID(QHttpRequestHeader& header)
{
	qDebug() << "checkID !!!";
	for (int i = 0; i < recVec->size(); i++) {
		ReceiverInfo* tmp = recVec->at(i);
		if (tmp->sessionID == header.value("SessionID") &&
		    tmp->fileName == header.value("Name") ) {
//		    tmp->fileSize == header.value("Content-Length").toInt()) {
			infoFound = tmp;
			return true;
		}
	}
	return false;
}


void Receiver::slotReceiveData()
{
	QTcpSocket* sock = m_sock;

	qDebug() << "SLOT_RECEIVE_DATA";
	
	
	QFile saveTo(targetPath + "/" + infoFound->fileName);

	if (!fileCheckDone) {
		if (saveTo.exists()) {
			KMessageBox::error(this,i18n("File %1 exists already.\nChoose another filename.",(infoFound->fileName)));
			QString newfileName = KFileDialog::getSaveFileName(KUrl(targetPath),"*",this, tr("Select File"));	
			saveTo.setFileName(newfileName);
			if (QString(targetPath + "/" + infoFound->fileName) == newfileName)
				saveTo.remove();
		}
		fileCheckDone = true;
	}

	if (!saveTo.open(QIODevice::ReadWrite | QIODevice::Append)) {
		 KMessageBox::error(this,i18n("Failed to create file %1 in %2.", infoFound->fileName,
						targetPath),i18n("Cannot create file..."));
		 disconnect(m_sock,SIGNAL(readyRead()), this,SLOT(headRead()));
		 return;
	}

	qDebug() << "file is open, filesize= " << saveTo.size();

	quint64 read;

	if (progress == 0) {
		progress = new QProgressDialog("Transfer...","cancel",0,100,this);
		progress->show();
		
//		recNotify= new KNotification ( "incomingFileTransfer" );
//		recNotify->setText( "File Transfer: " );
//		recNotify->setPixmap( QPixmap("network") );
	//	recNotify->sendEvent();

		
	}

	qDebug() << "Bytes to write available(before iteration): " << sock->bytesAvailable();
	disconnect(m_sock,SIGNAL(readyRead()), this,SLOT(slotReceiveData()));

	int count = 0;
	while(sock->bytesAvailable() > 0) {
		qDebug() << "\nWritecount: " << count++;
		qDebug() << "Bytes to write available: " << sock->bytesAvailable();
		char buf[8192];
		read = sock->read(buf,sizeof(buf));
		qDebug() << read << "bytes read!";
		readall+=read;
		quint64 written = saveTo.write(buf,read);
//		saveTo.flush();
		qDebug() << written << "bytes written!";
		slotDataReceiveProgress(readall);
	}
	connect(m_sock,SIGNAL(readyRead()), this,SLOT(slotReceiveData()));
	
	if (readall == infoFound->fileSize) {
		sendPayloadReceived(m_sock);
		recVec->remove(recVec->indexOf(infoFound));
		delete infoFound;
		infoFound = NULL;
		disconnect(m_sock,SIGNAL(readyRead()), this,SLOT(slotReceiveData()));
		m_sock = NULL;
		readall = 0;
		if (progress)
			delete progress;
		progress = 0;
		fileCheckDone = false;
	}
}

void Receiver::slotDataReceiveProgress(long done)
{
	qDebug() << "read: " << done;
	qDebug() << "total: " << infoFound->fileSize;
	float prog = ((float) done / (float) infoFound->fileSize) * 100.0;
	qDebug() << "prog: " << prog;
	progress->setValue(prog);
//	recNotify->setText( "File Transfer: " + QString::number(prog) + "%");
//	recNotify->update();
	

}


void Receiver::sendPayloadReceived(QTcpSocket* sock)
{
	QHttpResponseHeader resp;

        resp.setStatusLine(200,"Payload Received");
        resp.setValue("Date",QDate::currentDate().toString());
        resp.setValue("Connection","close");

        QByteArray head;
        head.append(resp.toString().toLatin1());
        sock->write(head);
}

void Receiver::setTargetPath(QString path)
{
	targetPath = path;
}

QString Receiver::getTargetPath()
{
	return targetPath;
}

