/***************************************************************************
 *   Copyright (C) 2004 by yunfan                                          *
 *   yunfan_zg@163.com                                                     *
 *                                                                         *
 *   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-1307, USA.             *
 ***************************************************************************/
 
#include "evaconnecter.h"
#include <qtimer.h> 
#include <qmutex.h>
#include <stdlib.h>

#define POOL_CHECK_INTERVAL  10000

EvaConnecter::EvaConnecter(EvaNetwork *network)
{
	connecter = network;
	connectionReady = false;
	QObject::connect(connecter, SIGNAL(isReady()), this, SLOT(isReadySlot()));
	QObject::connect(connecter, SIGNAL(dataComming(int)), this, SLOT(dataCommingSlot(int)));
	QObject::connect(connecter, SIGNAL(exceptionEvent(int)), this, SIGNAL(networkException(int)));
	
        outPool.setAutoDelete(true);
        inPool.setAutoDelete(false);
	
	timer = new QTimer(this);
	QObject::connect(timer, SIGNAL(timeout()), this, SLOT(packetMonitor()));
	timer->start(POOL_CHECK_INTERVAL, false); // every 10  second check two pools
}

EvaConnecter::~EvaConnecter()
{
	delete connecter;
	if(timer->isActive())
		timer->stop();
	delete timer;
}

void EvaConnecter::append(OutPacket *out)
{
	QMutex mutex;
	mutex.lock();
	sendOut(out);   // force to send
	if(out->needAck())
		outPool.append(out);
	mutex.unlock();
}

InPacket *EvaConnecter::getInPacket()
{
	if(inPool.count() <= 0 ){ 
		emit packetException(-1);
		return NULL;
	}
	return inPool.take();
}

void EvaConnecter::redirectTo(const int ip, const short port)
{	
	if(connecter->connectionType()!= EvaNetwork::HTTP_Proxy){
		connectionReady = false;
		connecter->setServer(QHostAddress(ip), port==-1?connecter->getHostPort():port);
		//connect();
	}else{
		connecter->setServer(connecter->getHostAddress(), connecter->getHostPort());
		connecter->setDestinationServer(QHostAddress(ip).toString(), 443); // always 443 for http proxy
		//connecter->newURLRequest();
	      }
	connect();
}

void EvaConnecter::connect()
{
	connecter->connect();
}

void EvaConnecter::stop()
{
	if(timer->isActive())
		timer->stop();	
}

void EvaConnecter::sendOut( OutPacket *out)
{
	if(timer->isActive())
		timer->stop();
	if(!connectionReady) return;
	unsigned char *buf = (unsigned char *)malloc(MAX_PACKET_SIZE * sizeof(unsigned char));
	int len;
	
	out->fill(buf, &len); 	
	connecter->write((char *)buf, len);
        //printf("len:%d\n",len);
	free(buf);
	if(!timer->isActive())
		timer->start(POOL_CHECK_INTERVAL, false);
}

void EvaConnecter::removePacket(const int hashCode)
{
	QMutex mutex;
	mutex.lock();
	for( uint i = 0; i < outPool.count(); i++){
		if(outPool.at(i)->hashCode() == hashCode){
                        //printf("removed\n");
			outPool.remove(i);
			--i;
		}
	}
	mutex.unlock();
}

void EvaConnecter::removeOutRequests(const short cmd)
{
	QMutex mutex;
	mutex.lock();
	for( uint i = 0; i < outPool.count(); i++){
		if(outPool.at(i)->getCommand() == cmd){
                        //printf("removed\n");
			outPool.remove(i);
			--i;
		}
	}
	mutex.unlock();	
}

void EvaConnecter::isReadySlot()
{
	connectionReady = true;
	emit isReady();
}

void EvaConnecter::dataCommingSlot(int len)
{
	QMutex mutex;
	mutex.lock();
	char * rawData =  (char *)malloc((len+1)*sizeof(char));   
	connecter->read(rawData, len);
	InPacket *packet = new InPacket((unsigned char *)rawData, len); 
	free(rawData);       
        removePacket(packet->hashCode());
	
	if(packet->getCommand() == QQ_CMD_KEEP_ALIVE)
		removeOutRequests(QQ_CMD_KEEP_ALIVE);
		
	if(packet->getCommand() == QQ_CMD_GET_FRIEND_ONLINE)
		removeOutRequests(QQ_CMD_GET_FRIEND_ONLINE);
		
        inPool.append(packet);	
	mutex.unlock();
	if(timer->isActive())
		timer->stop();
	emit newPacket();
	if(!timer->isActive())
		timer->start(POOL_CHECK_INTERVAL, false);
}

void EvaConnecter::packetMonitor()
{
	QMutex mutex;
	mutex.lock();
        //printf("timer. outPool:%d\n", outPool.count());
	for ( uint i=0;  i < outPool.count(); i++ ){
		if(outPool.at(i)->needResend()){
			sendOut(outPool.at(i));
// 			if(!outPool.at(i)->needAck()){
// 				removePacket(outPool.at(i)->hashCode());
// 				i--;
// 				continue;
// 			}
		}else{
			short cmd = outPool.at(i)->getCommand();
			removePacket(outPool.at(i)->hashCode());
			mutex.unlock();
			emit packetException(cmd);
			return;
		}
	}
//	printf("timer. inPool:%d\n", inPool.count());
	if(inPool.count()>0){
		emit newPacket();
	}
	mutex.unlock();
}





