/***************************************************************************
 *   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 NOMP2PBASE_H
#define NOMP2PBASE_H

#include <qobject.h>
#include <qiodevice.h>
#include <qfile.h>
#include <qptrlist.h>
#include <qstringlist.h>
#include <qmutex.h>
#include "knateonbuffer.h"

class QFile;
class QSocket;
class QTimer;
class QStringList;
class SQLiteDB;

class NOMP2PBase : public QObject {
	Q_OBJECT
    public:
	enum FILETYPE { SEND, RECEIVE };
    enum USEDIP { MYIP, YOURIP };
    enum STATUS { STOP, START, END };
    enum CONNECTTYPE { SERVER, CLIENT };
	
	NOMP2PBase( QObject *parent, const char *name );
	~NOMP2PBase();

    /*! 서버에 접속 */
    void connectToServer( const QString &sHost, const int nPort );
    void connectToFRServer( const QString &sHost, const int nPort );
    
    void setFileName( QString name ) { sFileName = name; }
	void setFilePath( QString path ) { sFilePath = path; }
	void setFileSize( QIODevice::Offset size ) { fFileSize = size; }
	void setFileCookie( QString cookie ) { sFileCookie = cookie; }
	void setP2PCookie( QString cookie ) { sP2PCookie = cookie; }
	void setFRCookie( QString cookie ) { sFRCookie = cookie; }
	virtual void setSocket( int nSocket );
	virtual void setSocket( QSocket *socket );
    void setMyID( const QString &id ) { sMyID = id; }
    void setYourID( const QString &id ) { sYourID = id; }
    void setMyIP( const QString &ip ) { sMyIP = ip; }
    void setYourIP( const QString &ip ) { sYourIP = ip; }
    void setMyPort( const QString &port ) { sMyPort = port; }
    void setYourPort( const QString &port ) { sYourPort = port; }
    void setType( FILETYPE type ) { eType = type; }
    
    /*! 현재 접속한 소켓이 내 소켓인지 상대 소켓인지 설정 */
    void setConnectYourSocket( bool bUse )
        {
            if ( bUse )
                eUsedIP = YOURIP;
            else
                eUsedIP = MYIP;
        }
    
    /*! 전송 시작 상태 */
    void setStatusStart() { eStatus = START; }
    /*! 전송 완료 상태 */
    void setStatusEnd() { eStatus = END; }
    void setConnectType( CONNECTTYPE connectType ) { eConnectType = connectType; }
    void setFRIP( const QString &ip ) { sFRIP = ip; }
    void setFRPort( const QString &port ) { sFRPort = port; }
    
    QString getFileName() { return sFileName; }
	QString getFilePath() { return sFilePath; }
	QIODevice::Offset getFileSize() { return fFileSize; }
	FILETYPE getType() { return eType; }
    CONNECTTYPE getConnectType() { return eConnectType;}
    
	QString getFileCookie() { return sFileCookie; }
	QString getP2PCookie() { return sP2PCookie; }
	QString getFRCookie() { return sFRCookie; }
	QSocket *getSocket() { return pSocket; }
    QString getMyID() { return sMyID; }
    QString getYourID() { return sYourID; }
    QString getMyIP() { return sMyIP; }
    QString getYourIP() { return sYourIP; }
    QString getMyPort() { return sMyPort; }
    QString getYourPort() { return sYourPort; }

    void close() { fFile.close(); }
	
	bool isOverWrite() { return bOverWrite; }
	bool isDone() { return ( getFileSize() == fFile.size() ); }
    bool isStatusStop() { return ( eStatus == STOP ); }
    bool isStatusStart() { return ( eStatus == START ); }
    bool isStatusEnd() { return ( eStatus == END ); }

    /*! 현재 접속된 소켓이 상대편의 Socket인가? */ 
    bool isYourSocket() { return ( eUsedIP == YOURIP ); }

// 	void startTimer();
	
    NOMP2PBase *getNOMP2PBaseByFileCookie( const QString &sFileCookie );
    NOMP2PBase *getNOMP2PBaseByP2PCookie( const QString &sP2PCookie );
    NOMP2PBase *getNOMP2PBaseByFRCookie( const QString &sFRCookie );

    void sendATHC( const QString &sMyID, const QString &sYourID, const QString &sP2PCookie, int nNegotiationPort );

    /*! ex) sCommand : "ATHC|sender@nate.com receiver@nate.com 12222222:2222 6004 0\r\n" */ 
    void addQueue( const QString &sCommand ) { slCommandQueue.append(sCommand); }

protected:
    QString sMyID;
    QString sYourID;
    QString sMyIP;
    QString sYourIP;
    QString sMyPort;
    QString sYourPort;
    QString sFRIP;
    QString sFRPort;
    
    FILETYPE eType;
    USEDIP eUsedIP;
    STATUS eStatus;
    CONNECTTYPE eConnectType;
    
	QFile	fFile;
	void fileOpen();
	virtual Q_LONG fileWrite( const char * data, Q_ULONG len );
// 	virtual Q_LONG fileRead( char * data, Q_ULONG maxlen );
	virtual void setOverWrite( bool overwrite );
	virtual void setOffset( QIODevice::Offset offset );
	 
	/*! Overwrite? */
	bool bOverWrite;
	
	/*! 파일명 */
	QString sFileName;
	
	/*! 파일저장 or 읽을 디렉토리 */
	QString sFilePath;
	
	QIODevice::Offset fFileSize;
	QIODevice::Offset fFileOffset;
    QIODevice::Offset fFileSumSize;
		
	/*! P2P Socket */
	QSocket *pSocket;
	QString sFileCookie;
	QString sP2PCookie;
	QString sFRCookie;
	QTimer *pP2PTimer;

    virtual void gotATHC( QStringList &slCommand );
	virtual void gotACCEPT( QStringList &slCommand );
	virtual void gotINFO( QStringList &slCommand );
	virtual void gotSTART( QStringList &slCommand );
	virtual void gotDATA( QStringList &slCommand );
	virtual void gotEND( QStringList &slCommand );
	virtual void gotFRIN( QStringList &slCommand );

    void sendCommand( const QString &sPrefix, const QString &sBody, unsigned TID = 0 );
    void sendBinData( const char *pRawData, Q_ULONG nByte );

    void setTID( unsigned int TID ) { nTID = TID; }
    unsigned int getTID() { return nTID++; }

    void sendATHC();
    void sendACCEPT();
    void sendINFO();
    void sendSTART();
    void sendEND();

	/*! 6004 네고를 위한 포트 */
	unsigned int getNegoPort() { return nNegoPort; }
	void setNegoPort( unsigned int NegoPort ) { nNegoPort = NegoPort; }
	
	/*! 바이너리 데이터 덩어리 크기 */
	Q_ULONG getPacketSize() { return nPacketSize; }
	void setPacketSize( Q_ULONG size ) { nPacketSize = size; }
	
	/*! 바이너리 전송 인가? */
	bool isBin() { return bBin; }
	void setBin( bool enable ) { bBin = enable; }

    /*! 데이터 전송 패킷 누적 */
	SQLiteDB*               pSQLiteDB;

private:
    /*! 바이너리 전송 인가? */
    bool bBin;

    /*! 바이너리 수신 버퍼 */
    char *pPacketData;
    Q_ULONG nPacketSize; /*! 전체 프로토콜 패킷 크기, ... DATA 8192 ... */
    Q_ULONG nPacketSum; /*! 소켓 패킷 누적 값 */ 

    char *pSocketRestData; /*! 프로토콜 패킷을 만들고 남은 데이터 */
    Q_ULONG nSocketRestSize;

    unsigned int nTID;
	unsigned int nNegoPort;
    QStringList slCommandQueue;

    KNateonBuffer qBuffer;
	QMutex mutex;

protected slots:
// 	virtual void slotP2PTimeout();
	virtual void slotConnected();
	virtual void slotFRConnected();
	virtual void slotReadyRead();
// 	virtual void slotDisconnected();
	
	/*! 파일전송이 취소 되면...*/
	void slotCancel();

    /*! 접속 에러가 나면... */
    void slotError( int nErrNo );
    
    /*! 접속 timer 에러 */
    void slotConnectError();
    
    /*! 파일전송 */
    void slotWriteToSocket( int nSocket );
    
signals:
//     void P2PTimeout( NOMP2PBase * );

    /*! Receiver */
    void signalGotATHC( NOMP2PBase * );

    /*! Sender */
    void signalGotSTART();
    void signalGotEND();
    void OutgoingMessage( const QString & );
    void IncomingMessage( const QString & );
    void tryREFR( const QString & sP2PCookie );
    void sendRFR( const QString & sP2PCookie );
    void sendREQCFR( const QString & sCommand );
    void updateProgress( const QString & sFileCookie, const unsigned long nByte );
    void endProgress( const QString & sFileCookie );
};
#endif
