/***************************************************************************
 *   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.             *
 ***************************************************************************/

#include "p2pserver.h"
#include "nomhttpproxy.h"

P2PServer::P2PServer(QObject *parent, const char *name)
: P2PConnection(parent, name),
m_server(0),
pCurrentAccount(0),
m_pHttpProxy(0)
{
	m_clients.setAutoDelete( FALSE );
	m_SendFileInfo.setAutoDelete( FALSE );
    m_P2PSocketList.setAutoDelete( false );
}


P2PServer::~P2PServer()
{
}

void P2PServer::startServer()
{
	if (m_server != 0) return; // sanity check

	m_server = new ServerSocket(m_nPort, this);
	if (!m_server->ok())
	{
		delete m_server;
		m_server = 0;
		return;
	}

	QObject::connect(m_server, SIGNAL(newClient(QSocket*)), this, SLOT(slotNewClient(QSocket*)));
}

void P2PServer::stopServer()
{
	QPtrDictIterator<Client> iter(m_clients);
	for (; iter.current() != 0; ++iter)
	{
		// disconnect the socket's signals from any slots or signals
		iter.current()->socket()->disconnect();
	}

	m_clients.clear(); // delete all clients (m_clients has autodelete ON)

	delete m_server;
	m_server = 0;
}


void P2PServer::slotNewClient(QSocket* socket)
{
	Client* client = new Client( socket );
	m_clients.insert(socket, client);
	
	// connect(socket, SIGNAL(connectionClosed()), this, SLOT(slotClientDisconnected()));
	// connect(socket, SIGNAL(readyRead()), this, SLOT(slotSocketRead()));

//     P2PSocket *pP2PSocket = new P2PSocket( socket, "p2psocket" );
//     connect( pP2PSocket, SIGNAL( IncomingMessage( const QString & ) ), SLOT( slotIncomingMessage( const QString & ) ) );
//     connect( pP2PSocket, SIGNAL( OutgoingMessage( const QString & ) ), SLOT( slotOutgoingMessage( const QString & ) ) );
//     connect( pP2PSocket, SIGNAL( gotSocketDPCookie( int, const QString & ) ), SLOT( slotGotSocketDPCookie( int, const QString & ) ) );
    
//     m_P2PSocketList.append( pP2PSocket );

    emit gotNewClient( socket );
	
	SendFileInfo *pSendFileInfo = client->fileInfo();
	if ( pSendFileInfo )
		if ( !pSendFileInfo->isConnected() )
			pSendFileInfo->setConnected();
}

void P2PServer::slotClientDisconnected()
{
	QObject* sender = const_cast<QObject*>(QObject::sender());
	QSocket* socket = static_cast<QSocket*>(sender);

	// qDebug("File Transfer :: client disconnected");

	//disconnect signals
	socket->disconnect();

	// remove from dict
	Client* client = m_clients.take(socket);

	delete client;
}


void P2PServer::slotSocketRead()
{
	QObject* sender = const_cast<QObject*>(QObject::sender());
	QSocket* socket = static_cast<QSocket*>(sender);

    Q_ULONG nByte = socket->bytesAvailable(); 
	char *str;
	str = (char *)malloc( nByte + 1 );
	memset( str, 0x00, nByte + 1 );
	socket->readBlock ( str, nByte );

    kdDebug() << "GET_DATA : [" << str << "]" << endl;
    emit IncomingMessage("[ P2P_S ]-{" + QString( str ) + "}-");      

    if ( strncmp( str, "ATHC", 4) == 0 ) {
	    disconnect( socket, 0, 0, 0 );
        /*! ex) ATHC 0 [Sender ID] [Receiver ID] [DP Cookie] 6004 0 */

        kdDebug() << "Found ATHC!" << endl;
        QStringList slCommand = QStringList::split( " ", str );
        kdDebug() << "DP Cookie : " << slCommand[4] << endl;
        
        char sATHC100[] = "ATHC 0 100 6004 0\r\n";
        socket->writeBlock( sATHC100, sizeof( sATHC100 ) - 1 );
        socket->flush();
        
        emit OutgoingMessage("[ P2P_S ]-{" + QString( sATHC100 ) + "}-");      
        emit gotServerATHC( socket, slCommand[4] );
	    // disconnect(socket, SIGNAL(readyRead()), this, SLOT(slotSocketRead()));
    }
    
#if 0
	Client* client = m_clients.find(socket);
	RecvFile( socket, client);
#endif
}


void P2PServer::slotSendATHCtoFR()
{
	QObject* sender = const_cast<QObject*>(QObject::sender());
	QSocket* socket = static_cast<QSocket*>(sender);

	Client* client = m_clients.find(socket);
	SendFileInfo* pSendFileInfo;
	pSendFileInfo = client->fileInfo();

	QString sCommand;
	sCommand = pSendFileInfo->getMyID();
	sCommand += " ";
	sCommand += pSendFileInfo->getYourID();
	sCommand += " ";
	sCommand += pSendFileInfo->getDPCookie();
	sCommand += " ";
	sCommand += pSendFileInfo->getFRCookie();
	sCommand += " ";
	sCommand += "6004";
	sCommand += " ";
	sCommand += "0";
	sCommand += "\r\n";
	sendCommand( socket, "ATHC", sCommand);

	if ( pSendFileInfo->isReceive() )
	{
		sCommand = "FILE";
		sCommand += " ";
		sCommand += "0";
		sCommand += " ";
		sCommand += "ACCEPT";
		sCommand += " ";
		sCommand += pSendFileInfo->getSSCookie();
		sCommand += " ";
		sCommand += "0";
		sCommand += "\r\n";
		sendCommand_noTid( socket, sCommand);
	}
#ifdef NETDEBUG
	kdDebug() << "XXXXXXXX [" << sCommand << "]" << endl;
#endif
}

void P2PServer::slotSendATHC()
{
	QObject* sender = const_cast<QObject*>(QObject::sender());
	QSocket* socket = static_cast<QSocket*>(sender);

	SendFileInfo* pSendFileInfo;
	Client* client = m_clients.find(socket);
	pSendFileInfo = client->fileInfo();
	
	if ( !pSendFileInfo->isConnected() )
	{
		pSendFileInfo->setConnected();
	
		QString sCommand;
		sCommand = pSendFileInfo->getMyID();
		sCommand += " ";
		sCommand += pSendFileInfo->getYourID();
		sCommand += " ";
		sCommand += pSendFileInfo->getDPCookie();
		sCommand += " ";
		sCommand += "6004";
		sCommand += " ";
		sCommand += "0";
		sCommand += "\r\n";
		sendCommand( socket, "ATHC", sCommand);
	}
}

void P2PServer::slotConnectP2PFR(const QStringList & slCommand)
{
	SendFileInfo *pSendFileInfo = getSendFileInfoByID( slCommand[2] );

	if ( !pSendFileInfo )
		pSendFileInfo = new SendFileInfo(slCommand[2], pCurrentAccount->getMyNateID(), slCommand[7], slCommand[8]);
	else
	{
		pSendFileInfo->setDPCookie( slCommand[7] );
		pSendFileInfo->setFRCookie( slCommand[8] );
	}

	QStringList slIPPort = QStringList::split( QString(":"), slCommand[6] );

	QSocket* socket = new QSocket(parent());
	
	QObject::connect( socket, SIGNAL( connected() ), this, SLOT( slotSendATHCtoFR() ) );
	QObject::connect( socket, SIGNAL( readyRead() ), this, SLOT( slotSocketReadFR() ) );
	QObject::connect( socket, SIGNAL( connectionClosed() ), this, SLOT( slotClientDisconnected() ) );
	
	socket->connectToHost( slIPPort[0], slIPPort[1].toInt() );

	Client* client = new Client( socket );

	pSendFileInfo->setSocket(socket);
	pSendFileInfo->setConnected();

	client->setSendFileInfo( pSendFileInfo );
	m_clients.insert(socket, client);
}

void P2PServer::slotSocketReadFR()
{
	QObject* sender = const_cast<QObject*>(QObject::sender());
	QSocket* socket = static_cast<QSocket*>(sender);

	Client* client = m_clients.find(socket);

	RecvFile( socket, client);
}

/*!
  slCommand :
  CTOC 0 user01@nate.com 41 REQC NEW 192.168.0.1:0 10008348086:1105
  CTOC 0 user01@nate.com 44 REQC RES 192.168.0.1:5004 10008348086:1105
*/
void P2PServer::slotConnectToP2P(const QStringList & slCommand)
{
	SendFileInfo *pSendFileInfo;

	if (slCommand[5] == "NEW") {
		/*! REQC NEW 를 받았을때, 파일보내기, 상대가 받을때, 내가 보낼때 */
		pSendFileInfo = getSendFileInfoByID( slCommand[2] );
		if ( !pSendFileInfo )
			return;
		pSendFileInfo->setSend();
	} else {
		/*! REQC RES 를 받았을때, 파일받기, 상대가 보낼때, 내가 받을때 */
		pSendFileInfo = getSendFileInfoByDPCookie( slCommand[7] );
		if ( !pSendFileInfo )
			return;
		pSendFileInfo->startTimer();
		QObject::connect( pSendFileInfo, SIGNAL( P2PTimeout(SendFileInfo*) ), this, SLOT( slotTimeOut(SendFileInfo*) ) );
		pSendFileInfo->setReceive();
	}

	QStringList slIPPort = QStringList::split( QString(":"), slCommand[6] );

	QSocket* socket = new QSocket(parent());
	
	QString sServer;
	int nPort = 0;
	if ( pCurrentAccount->getProxyType() == 2 ) {
		/*! HTTP Proxy */
		m_pHttpProxy = new NOMHTTPProxy( "pri.nate.com", 5004 );
		sServer = pCurrentAccount->getProxyServer();
		nPort = pCurrentAccount->getProxyPort();
	} else {
		sServer = slIPPort[0];
		nPort = slIPPort[1].toInt();
	}
	socket->connectToHost( sServer, nPort );

	Client* client = new Client( socket );
	QObject::connect( socket, SIGNAL( connected() ), this, SLOT( slotSendATHC() ) );
	QObject::connect( socket, SIGNAL( readyRead() ), this, SLOT( slotSocketRead() ));
	QObject::connect( socket, SIGNAL( connectionClosed() ), this, SLOT( slotClientDisconnected() ) );
	
	pSendFileInfo->setDPCookie( slCommand[7] );
	pSendFileInfo->setSocket(socket);

	client->setSendFileInfo( pSendFileInfo );
	m_clients.insert(socket, client);
}

void P2PServer::slotTimeOut(SendFileInfo * pSendFileInfo)
{
	if ( !pSendFileInfo->isConnected() )
		emit connTimeOut( pSendFileInfo );
}

void P2PServer::slotReceivedREFR(const QStringList & slCommand)
{
	SendFileInfo *pSendFileInfo = getSendFileInfoByDPTid( slCommand[1].toInt() );

	QSocket* socket = new QSocket(parent());
	socket->connectToHost( slCommand[2], slCommand[3].toInt() );

	pSendFileInfo->setSocket(socket);
	pSendFileInfo->setReceive();
	pSendFileInfo->setFRIP( slCommand[2] );
	pSendFileInfo->setFRPort( slCommand[3].toInt() );
	pSendFileInfo->setFRCookie( slCommand[4] );

	Client* client = new Client( socket );
	client->setSendFileInfo( pSendFileInfo );

	m_clients.insert(socket, client);

	QObject::connect( socket, SIGNAL( connected() ), this, SLOT( slotSendFRIN() ) );
	QObject::connect( socket, SIGNAL( readyRead() ), this, SLOT( slotSocketRead() ));
	QObject::connect( socket, SIGNAL( connectionClosed() ), this, SLOT( slotClientDisconnected() ) );
}

void P2PServer::slotSendFRIN()
{
	QObject* sender = const_cast<QObject*>(QObject::sender());
	QSocket* socket = static_cast<QSocket*>(sender);

	Client* client = m_clients.find(socket);
	SendFileInfo* pSendFileInfo;
	pSendFileInfo = client->fileInfo();
	pSendFileInfo->setConnected();
	pSendFileInfo->setReceive();

	QString sCommand;
	sCommand = "FRIN";
	sCommand += " ";
	sCommand += "0";
	sCommand += " ";
	sCommand += pSendFileInfo->getYourID();
	sCommand += " ";
	sCommand += pSendFileInfo->getFRCookie();
	sCommand += "\r\n";
	sendCommand_noTid( socket, sCommand);
}

void P2PServer::slotIncomingMessage( const QString & message )
{
    emit IncomingMessage( message );
}

void P2PServer::slotOutgoingMessage( const QString & message )
{
    emit OutgoingMessage( message );
}

void P2PServer::slotGotSocketDPCookie( int socket, const QString & dpcookie )
{
    emit gotSocketDPCookie( socket, dpcookie );
}


#include "p2pserver.moc"
