/***************************************************************************
 *   Copyright (C) 2008 by SK Communications.                              *
 *   http://kldp.net/projects/nateon/                                      *
 *                                                                         *
 *   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, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifndef P2PCONNECTION_H
#define P2PCONNECTION_H

// Qt includes
#include <qobject.h>
#include <qsocket.h>
#include <qtextstream.h>
#include <qptrdict.h>
#include <kdebug.h>
#include <qfile.h>
#include <qdir.h>
#include <qmutex.h>
#include <qsocketnotifier.h>

// local includes
// #include "servermainwindow.h"
#include "serversocket.h"
#include "sendfileinfo.h"
#include "knateonbuffer.h"

// forward declarations
class QSocket;
class ServerSocket;
class SendFileInfo;
class QFile;
class NOMP2PBase;

class Client
{
public:
	Client(QSocket* socket)
		: m_socket(socket),
		m_num(++m_count),
		m_pSendFileInfo(0),
		bBin(false),
		nPacketNum(2),
		baPacket(0),
		ulWriteSum(0),
		uiPacketSum(0),
		uiPacketSize(0)
	{};

	~Client() {
		/*
		  if ( m_socket )
		  m_socket->close();
		*/
	}
	/*! 할당된 소켓 */
	inline QSocket* socket() { return m_socket; }

	/*! 파일 정보 */
	inline SendFileInfo* fileInfo() { return m_pSendFileInfo; }
	void setSendFileInfo(SendFileInfo* pSendFileInfo) { m_pSendFileInfo = pSendFileInfo; }

	/*! 파일 ID */
	inline int number() { return m_num; }

	/*! 파일 전송 모드 */
	void setBin() { bBin = true; }
	void setText() { bBin = false; }
	bool isBin() { return bBin; }

	/*! FILE 번호 DATA */
	int getPacketNum() { return nPacketNum; }
	void setPacketNum( int nNo ) { nPacketNum = nNo; }
	int incPacketNum() { return nPacketNum++; }

	/*! 바이너리로 파일 저장 */
	void addPacket(char *str, int size) { baPacket.add(str, size); uiPacketSum += size;}
	// unsigned long getPacketSum() { return ulPacketSum; }
	unsigned long getPacketSum() { return ( ulWriteSum + uiPacketSum ); }
	KNateonBuffer& getPacket() { return baPacket; }
	void removePacket(int size) { 
		baPacket.remove(size);
		uiPacketSum -= size;
	}
	unsigned long getFileSize() { return m_pSendFileInfo->getFileSize(); }

	/*! 파일 전송 완료? */
	bool isDone() {
		return ( getFileSize() <= ( ulWriteSum + uiPacketSum ) );
		// return ( getFileSize() == ulWriteSum );
	}

	/*! 파일 저장 */
	void openSaveFile(QString pPath);
	void writeSaveFile(const QByteArray &qArray, unsigned long size);
	void closeSaveFile();
	
	void setPacketSize( unsigned int Size ) { 
		uiPacketSize = Size;
	}
	unsigned int getPacketSize() { return uiPacketSize; }
	unsigned int getPacketSumSize() { return uiPacketSum; }

	void init() {
		if ( !baPacket.isEmpty() ) {
			baPacket.truncate(0);
			baPacket.resize(0);
		}
		ulWriteSum = 0;
		uiPacketSum = 0;
		uiPacketSize = 0;
	}
	
protected:
    static int m_count;
    QSocket* m_socket;
	int m_num;
	SendFileInfo* m_pSendFileInfo;
    bool bBin;
	int nPacketNum; /*! "FILE [tid] DATA ..." 에서 tid */
	KNateonBuffer baPacket; /*! 단위 패킷 저장 소 */
	unsigned long ulWriteSum; /*! 파일에 Write 한 Sum */
	unsigned int uiPacketSum; /*! 단위 패킷 크기를 채우기 위한 Sum */
	unsigned int uiPacketSize; /*! 단위 패킷 크기 "FILE [tid] DATA size\r\n" 에서 size */ 
    QFile qFile;
};


/**
   @author Doo-Hyun Jang <ring0320@nate.com>
*/
class P2PConnection : public QObject
{
Q_OBJECT
public:
    P2PConnection(QObject *parent = 0, const char *name = 0);
    ~P2PConnection();

    QString getSendFile() { return sSendFile; }
    unsigned long getStartPos() { return ulStartPos; }
    void addSendFileInfo(SendFileInfo* pSendFileInfo);

    void setSendFile( QString SendFile ) { sSendFile = SendFile; }
    void setStartPos( unsigned long StartPos ) { ulStartPos = StartPos; }

    SendFileInfo* getSendFileInfoBySSCookie(QString sCookie);
    SendFileInfo* getSendFileInfoByDPCookie(QString sCookie);
    SendFileInfo* getSendFileInfoByID(QString sID);
    SendFileInfo* getSendFileInfoByDPTid(int Tid);
	SendFileInfo* getSendFileInfoBySocket(int Socket);

    virtual void gotATHC( const QStringList& slCommand, SendFileInfo* pSendFileInfo );

    int sendCommand(QSocket* pSocket, const QString& sPrefix, const QString& sText = "\r\n");
    void sendCommand_noTid(QSocket* pSocket, const QString& sText = "\r\n");
    int getTrid();
	void SendFile( QSocket* socket, Client* client, unsigned long ulStart );
    void RecvFile( QSocket* socket, Client* client );
    void sendAccept(SendFileInfo* pSendFileInfo);
    void sendReject(SendFileInfo* pSendFileInfo);

	QMutex mutex;
protected:
    QPtrDict<Client> m_clients;
    QPtrList<SendFileInfo> m_SendFileInfo;

protected slots:
	void slotSendFile( int nSocket );

private:
    int m_nTrid;
    QString sSendFile;
    unsigned long ulStartPos; /// 이어받기를 지원하기 위한 파일 시작 위치

signals:
    void updateProgress( const QString& sCookie, const unsigned long ulSum, const unsigned long ulTotal, const int nPercent );
    void finishTransfer( SendFileInfo* );
    void AcceptOk( SendFileInfo* );
    void OutgoingMessage(const QString& csMsg);
    void IncomingMessage(const QString& csMsg);
    void sendCTOCFR( SendFileInfo* );
    // void endTransfer();
};

#endif
