/***************************************************************************
 *   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 "evamain.h"

#include "evautil.h"

#include "evaapi.h"

#include "evaui.h"

#include "evachatwindowmanager.h"
#include "evasystemtray.h"

#include <qimage.h>
#include <qtimer.h>
#include <qtextcodec.h>
#include <qdatetime.h>
#include <qhostaddress.h>
#include <qmessagebox.h>
#include <qpopupmenu.h>
#include <kapplication.h>
#include <kaboutdata.h>
#include <kaboutapplication.h>

KAboutData * EvaMain::mAboutData = NULL;
EvaUser *EvaMain::user = NULL;
EvaImageResource *EvaMain::images = NULL;
EvaMain::EvaMain() :
	connecter(NULL),
	packetManager(NULL),
	numOfLostKeepAlivePackets(0),
	aboutEva(NULL),
	sysMenu(NULL),
	statusMenu(NULL),
	autoMenu(NULL),
	windowList(NULL)
{
	//path = argv[0];
	//user = NULL;
	loggedIn=false;
	deleteFromQQ = -1;
	codec = QTextCodec::codecForName("GBK");
	onlineFriendTimer = new QTimer();
	loginWin = new EvaLoginWindow(0);
	mainWin = new EvaMainWindow(0);
	tray = new EvaSystemTray(mainWin);
	initSettings();
	if(!doInitUI()){
		doQuit();
		//exit(0);
	}
	doSlotConnection();
	loginWin->show();
}

EvaMain::~EvaMain()
{
	delete loginWin;
	delete mainWin;
	delete packetManager;
	
	if(aboutEva) delete aboutEva;
}

void EvaMain::initSettings()
{
	global = new EvaGlobal();
	if(!global->loadImage()) {
		QMessageBox::information(0, i18n("Eva Initializing"), 
				i18n("Sorry, image resource cannot be loaded properly, check image directory please."));
		exit(0);
	}
	global->setFaceSize(QSize(16, 16));
	images = global->getImageResource();
	sysSetting = global->getEvaSetting();
	QObject::connect(images, SIGNAL(qqShowReady(const int)), this, SLOT(slotQQShowReady(const int)));
}

void EvaMain::doAbout()
{
	if(mAboutData){
		if(!aboutEva){
			aboutEva = new KAboutApplication(mAboutData, mainWin, "About", false);
		}
		aboutEva->setLogo(*(images->getIcon("EVA")));
		aboutEva->show();
	}	
}

void EvaMain::doQuit()
{
	if(loggedIn || packetManager)
		packetManager->doLogout();
	KApplication::kApplication()->quit();
}

bool EvaMain::doInitUI()
{
	// login window	
	loginWin->setLogo(images->getIcon("EVALOGO"));
	loginWin->setIcon(*images->getIcon("LOGO"));
	if(sysSetting){
		loginWin->setEvaSetting(sysSetting);
	}
	
	// main window
	mainWin->setBasicPixmaps(images->getIcon("SYSTEM_SETTING"), images->getIcon("OPEN"), images->getIcon("CLOSE"), 
				images->getIcon("NA"), images->getIcon("MSG"));
	mainWin->setStatusPixmaps(images->getIcon("ONLINE"), images->getIcon("OFFLINE"), 
				images->getIcon("LEAVE"), images->getIcon("INVISIBLE"));
	mainWin->setGroupMenu(images->getIcon("RENAME"), images->getIcon("ADD_GROUP"), images->getIcon("DEL_GROUP"), 
				images->getIcon("SHOW_ONLINE_BUDDIES"), images->getIcon("SHOW_ALL_BUDDIES"));
	mainWin->setBuddyMenu(images->getIcon("CHAT"), images->getIcon("DETAILS"), images->getIcon("HISTORY"), 
				images->getIcon("DEL_BUDDY"));
	initMenus();
	
	mainWin->setStatusMenu(statusMenu);
	mainWin->setSystemMenu(sysMenu);
	
	tray->setImagesResource(images);
	tray->setupMenus(sysMenu, statusMenu);
	
	EvaDetailsWindow::setImageResource(images);
	return true;
}

void EvaMain::initMenus()
{
	statusMenu = new QPopupMenu();
	statusMenu->insertItem(QIconSet(*(images->getIcon("ONLINE"))), i18n("Online"), this,SLOT(slotDoOnline()), -1);
	statusMenu->insertItem(QIconSet(*(images->getIcon("OFFLINE"))), i18n("Offline"), this,SLOT(slotDoOffline()), -1);
	statusMenu->insertItem(QIconSet(*(images->getIcon("LEAVE"))), i18n("Leave"), this,SLOT(slotDoLeave()), -1);
	statusMenu->insertItem(QIconSet(*(images->getIcon("INVISIBLE"))), i18n("Invisible"), this,SLOT(slotDoInvisible()), -1);
	
	sysMenu = new QPopupMenu();
	QPopupMenu *group = new QPopupMenu();
	group->insertItem(QIconSet(*(images->getIcon("UPLOAD_GROUPS"))), i18n("Upload Group"),this, SLOT(slotDoUploadGroups()), -1);
	group->insertItem(QIconSet(*(images->getIcon("DOWNLOAD_GROUPS"))), i18n("Download Group"),this, SLOT(slotDoDownloadGroups()), -1);
	
	sysMenu->insertItem(QIconSet(*(images->getIcon("GROUP"))), i18n("Group"),group);
	sysMenu->insertItem(QIconSet(*(images->getIcon("REFRESH_BUDDIES"))), i18n("Update Buddies"), this,SLOT(slotDoDownloadBuddies()), -1);
	sysMenu->insertItem(QIconSet(*(images->getIcon("SYSTEM_OPTIONS"))), i18n("System Options"),this, SLOT(slotRequestSystemSettingWindow()));
	sysMenu->insertItem(QIconSet(*(images->getIcon("CHANGE_USER"))), i18n("Change User"), this,SLOT(slotDoChangeUser()), -1);
	sysMenu->insertItem(QIconSet(*(images->getIcon("EVA"))), i18n("About Eva"), this,SLOT(doAbout()), -1);
	sysMenu->insertItem(QIconSet(*(images->getIcon("QUIT"))), i18n("Quit"), this,SLOT(doQuit()), -1);
}

void EvaMain::initUserLeaveMenu()
{
	if(!statusMenu) return;
	std::list<QString>::iterator iter;
	std::list<QString> autoList = user->getSetting()->getAutoReplyList();
	//if(!autoList.size()) return;
	
	autoMenu = new QPopupMenu();
	autoMenu->setCheckable(true);
	autoMenu->insertItem(QString(i18n("No Auto-Reply")), 0);
	int id=1;
	for(iter=autoList.begin(); iter!=autoList.end(); ++iter){
		autoMenu->insertItem(*iter, id++);
	}
	autoMenu->setItemChecked(user->getSetting()->getAutoReplySelectedIndex()+1, true);
	statusMenu->removeItemAt(2);
	statusMenu->insertItem(QIconSet(*(images->getIcon("LEAVE"))), i18n("Leave"), autoMenu, -1, 2);
	
	QObject::connect(autoMenu, SIGNAL(activated(int)), this,  SLOT(slotAutoReplyMenuActivated(int)));
}

void EvaMain::slotAutoReplyMenuActivated(int id)
{
	if(id==0)
		user->getSetting()->setAutoReplyEnabled(false);
	else
		user->getSetting()->setAutoReplyEnabled(true);
	user->getSetting()->setAutoReplySelectedIndex(id - 1);
	for(uint i=0; i <= user->getSetting()->getAutoReplyList().size(); i++){
		if((int)i==id)
			autoMenu->setItemChecked(i, true);
		else
			autoMenu->setItemChecked(i, false);
	}
	if(user->getStatus() != EvaUser::Eva_Leave)
		slotDoLeave();
}

void EvaMain::doSlotConnection()
{
	QObject::connect(onlineFriendTimer, SIGNAL(timeout()), this, SLOT(slotGetOnlineStatus()));
	QObject::connect(loginWin, SIGNAL(doLogin()), this, SLOT(slotDoLoginClick()));
	QObject::connect(loginWin, SIGNAL(doCancel()), this, SLOT(slotDoCancel()));
	
	QObject::connect(mainWin, SIGNAL(groupDeleted(const int)), this, SLOT(slotGroupDeleted(const int)));
	QObject::connect(mainWin, SIGNAL(groupAdded(QString, int)), this, SLOT(slotGroupAdded(QString, int)));
	QObject::connect(mainWin, SIGNAL(groupRenamed(QString, int)), this, SLOT(slotGroupRenamed(QString, int)));
	QObject::connect(mainWin, SIGNAL(deleteMeFrom(int)), this, SLOT(slotDeleteMeFrom(int)));
	QObject::connect(mainWin, SIGNAL(groupChanged(int, int)), this, SLOT(slotGroupChanged(int, int)));
	QObject::connect(mainWin, SIGNAL(requestAddBuddy(int)), this, SLOT(slotRequestAddBuddy(int)));
	
	QObject::connect(mainWin, SIGNAL(requestDelete(const int)), this, SLOT(slotRequestDelete(const int)));
	QObject::connect(mainWin, SIGNAL(requestDetails(const int)), this, SLOT(slotRequestDetails(const int)));
	QObject::connect(mainWin, SIGNAL(requestChat(const int)), this, SLOT(slotRequestChat(const int)));
	QObject::connect(mainWin, SIGNAL(requestSearch()), this, SLOT(slotRequestSearch()));
	QObject::connect(mainWin, SIGNAL(requestSystemMessages()), this, SLOT(slotRequestSystemMessages()));
	QObject::connect(mainWin, SIGNAL(requestHistory(const int)), this, SLOT(slotRequestHistory(const int)));
	
	QObject::connect(tray, SIGNAL(requestChat(const int)), this, SLOT(slotRequestChat(const int)));
	QObject::connect(tray, SIGNAL(requestSystemMessage()), this, SLOT(slotRequestSystemMessage()));
}

void EvaMain::initGroups()
{
	std::list<std::string> names = user->getGroupNames();
	std::list<std::string>::iterator iter;
	int i=0;
	for(iter = names.begin(); iter!= names.end(); ++iter){
		QString g = codec->toUnicode(iter->c_str());
		mainWin->addGroup(g, i++);
	}
	QString gAnonyms = codec->toUnicode(user->getAnonymousGroupName().c_str());
	QString gBlack = codec->toUnicode(user->getBlackGroupName().c_str());
	mainWin->addGroup(gAnonyms, user->getAnonymousIndex());
	mainWin->addGroup(gBlack, user->getBlackIndex());
}

void EvaMain::slotGetOnlineStatus()
{
	std::list<QQFriend>::iterator iter;
	std::list<QQFriend> list = (user->getFriendList()).getAllFriends();
	for(iter = list.begin(); iter != list.end(); ++iter){
		switch(iter->getStatus()){
		case QQ_FRIEND_STATUS_ONLINE:
			mainWin->changeToOnline(iter->getQQ());
			break;
		case QQ_FRIEND_STATUS_OFFLINE:
			mainWin->changeToOffline(iter->getQQ());
			break;
		case QQ_FRIEND_STATUS_LEAVE:
			mainWin->changeToLeave(iter->getQQ());
			break;
		case QQ_FRIEND_STATUS_INVISIBLE:
			mainWin->changeToInvisible(iter->getQQ());
			break;
		}	
	}	
}

void EvaMain::slotDoLoginClick()
{
	if(mainWin) mainWin->offline();
	if(tray) tray->setOffline();
	
	EvaServers *server = global->getEvaServers();
	QObject::connect(server, SIGNAL(isReady(QHostAddress)), SLOT(slotGotServer(QHostAddress)));
	server->fetchAddress(loginWin->getConnectionType() == EvaLoginWindow::UDP ? true: false);	
}

void EvaMain::slotGotServer(QHostAddress addr)
{
	QQServer = addr;
	if(loggedIn) slotDoLogout();
	if(packetManager) {
		packetManager->doLogout();
		delete packetManager;
	}
	if(windowList) delete windowList;
	
	mainWin->clearList();
	loginWin->hide();
	mainWin->show();
	tray->show();
	
	
	user = new EvaUser(loginWin->getQQ(),loginWin->getMd5Password());
	QString aname, bname;
	//QTextCodec *ucodec = QTextCodec::codecForName("utf8");
	//aname = ucodec->toUnicode(i18n("Anonymous"));
	//bname = ucodec->toUnicode(i18n("Black List"));
	aname = i18n("Anonymous");
	bname = i18n("Black List");
	user->setAnonymousGroupName(codec->fromUnicode(aname).data());
	user->setBlackGroupName(codec->fromUnicode(bname).data());
	user->getSetting()->loadSettings();
	images->setThemePath(user->getSetting()->getThemeDir());
	global->getSoundResource()->setSoundDir(user->getSetting()->getSoundDir());
	global->setFaceSize(QSize(user->getSetting()->getFaceSize()));
	
	if(loginWin->isHiddenLoginMode())
		user->setStatus(EvaUser::Eva_Invisible);
	else
		user->setStatus(EvaUser::Eva_Online);
	
	QString nick = codec->toUnicode(user->getDetails().at(ContactInfo::Info_nick).c_str());// if not exist, default "EVA" will be used	
	if(!user->loadGroupedBuddyList()){
		//QString name = ucodec->toUnicode(i18n("Buddy"));
		QString name = i18n("Buddy");
		user->newGroup(codec->fromUnicode(name).data()); // we must do this if cannot load from disk
	}else{
		nick = codec->toUnicode(user->getDetails().at(ContactInfo::Info_nick).c_str()); // once load, nick name should be right
		int faceId = atoi(user->getDetails().at(ContactInfo::Info_face).c_str());
		QPixmap *face = images->getFace(images->getFaceFileIndex(faceId));
		mainWin->setCaption(nick + " - Eva");
		mainWin->setIcon(*face);
		mainWin->setMainInfo(user->getQQ(), nick, face?face:images->getFace(0)); 
		initGroups();
		slotFriendListReady();
		std::list<QQFriend>::iterator iter;
		std::list<QQFriend> list = (user->getFriendList()).getAllFriends();
		for(iter = list.begin(); iter != list.end(); ++iter){
			mainWin->changeGroupTo(iter->getQQ(), iter->getGroupIndex());
		}
		tray->changeToolTip(user->getQQ(), nick, faceId);
	}
	
	EvaNetwork *network = NULL;
	switch(loginWin->getConnectionType()){
	case EvaLoginWindow::UDP:
		network = new EvaNetwork(QQServer, 8000, EvaNetwork::UDP);
		break;
	case EvaLoginWindow::TCP:
		network = new EvaNetwork(QQServer, 80, EvaNetwork::TCP);
		break;
	case EvaLoginWindow::HTTP_Proxy:
		network = new EvaNetwork(QHostAddress(loginWin->getProxyIP()), loginWin->getProxyPort(), EvaNetwork::HTTP_Proxy);
		network->setDestinationServer(QQServer.toString(), 443);
		//network->setAuthParameter(loginWin->getProxyUserName(),loginWin->getProxyPassword());
		network->setAuthParameter(loginWin->getProxyParam());
		break;
	}
	connecter = new EvaConnecter(network);
	QObject::connect(connecter, SIGNAL(isReady()), SLOT(slotConnectReady()));
	packetManager = new EvaPacketManager(user, connecter);
	QObject::connect(packetManager, SIGNAL(networkException(int)), this, SLOT(slotNetworkException(int)));
	QObject::connect(packetManager, SIGNAL(packetException(int)), this, SLOT(slotPacketException(int)));
	QObject::connect(packetManager, SIGNAL(serverBusy()), SLOT(slotDoLoginClick()));
	QObject::connect(packetManager, SIGNAL(wrongPassword()), SLOT(slotWrongPassword()));
		
	QObject::connect(packetManager, SIGNAL(loginOK()), SLOT(slotLoginOK()));
	QObject::connect(packetManager, SIGNAL(onlineReady()), SLOT(slotOnlineReady()));
	QObject::connect(packetManager, SIGNAL(offlineReady()), SLOT(slotOfflineReady()));
	QObject::connect(packetManager, SIGNAL(invisibleReady()), SLOT(slotInvisibleReady()));
	QObject::connect(packetManager, SIGNAL(leaveReady()), SLOT(slotLeaveReady()));	
	QObject::connect(packetManager, SIGNAL(friendStatusChanged(int)), SLOT(slotFriendStatusChanged(int)));	
	QObject::connect(packetManager, SIGNAL(friendListReady()), SLOT(slotFriendListReady()));
	QObject::connect(packetManager, SIGNAL(deleteMeReady(bool)), SLOT(slotDeleteMeReply( bool )));
	//QObject::connect(packetManager, SIGNAL(sentMessageResult(int, bool)), SLOT(slotSentMessageResult(int, bool)));
	QObject::connect(packetManager, 
			SIGNAL(txtMessage(int, bool, QString, QDateTime, const char,const bool, const bool, const bool, 
				const char , const char, const char)), 
			SLOT(slotTxtMessage(int, bool, QString, QDateTime, const char,const bool, const bool, const bool, 
				const char , const char, const char)));
	QObject::connect(packetManager, SIGNAL(friendGroupsReady()), SLOT(slotFriendGroupsReady()));
	QObject::connect(packetManager, SIGNAL(friendGroupsUploadReady(bool)), SLOT(slotFriendGroupsUploadReady(bool)));
	QObject::connect(packetManager, SIGNAL(deleteBuddyReady(int, bool)), SLOT(slotDeleteBuddyReady(int, bool)));		

	QObject::connect(packetManager, SIGNAL(myInfoReady()), SLOT(slotMyInfoReady()));
	QObject::connect(packetManager, SIGNAL(addBuddyReady()), SLOT(slotFriendListReady( )));
	QObject::connect(packetManager, SIGNAL(systemAddRequestApproved(int)), SLOT(slotFriendListReady( )));	

	QObject::connect(packetManager, SIGNAL(systemMeBeenAdded(int)), SLOT(slotSystemMeBeenAdded(int)));
	QObject::connect(packetManager, SIGNAL(systemAddMeRequest(int, QString)), SLOT(slotSystemAddMeRequest(int, QString)));
	QObject::connect(packetManager, SIGNAL(systemAddRequestApproved(int)), SLOT(slotSystemAddRequestApproved(int)));
	QObject::connect(packetManager, SIGNAL(systemAddRequestRejected(int, QString)), SLOT(slotSystemAddRequestRejected(int, QString)));
				
	QObject::connect(packetManager, SIGNAL(systemMeBeenAdded(int)), tray, SLOT(newSysMessage()));
	QObject::connect(packetManager, SIGNAL(systemAddMeRequest(int, QString)), tray, SLOT(newSysMessage()));
	QObject::connect(packetManager, SIGNAL(systemAddRequestApproved(int)), tray, SLOT(newSysMessage()));
	QObject::connect(packetManager, SIGNAL(systemAddRequestRejected(int, QString)), tray, SLOT(newSysMessage()));	
	
	if(user->getSetting()->isShowSystemBroadcastEnabled())
		QObject::connect(packetManager, SIGNAL(systemNotification(int, QString)), tray, SLOT(newSysMessage()));
	
	initGroups();
	
	windowList = new EvaChatWindowManager(images, user->getSetting(), nick, user->getQQ());
	QObject::connect(packetManager, SIGNAL(txtMessage(int, bool, QString, QDateTime, const char, 
			const bool, const bool, const bool, const char , const char, const char)), windowList, 
			SLOT(slotReceivedMessage(int, bool, QString, QDateTime, const char,const bool, const bool, const bool, 
			const char , const char, const char)));
	QObject::connect(packetManager, SIGNAL(sentMessageResult(int, bool)), windowList, SLOT(slotSendResult(int, bool)));
	QObject::connect(windowList, SIGNAL(requestDetails(const int)), this, SLOT(slotRequestDetails(const int)));	
	QObject::connect(windowList, SIGNAL(sendMessage(const int , const bool , QString &, const char , 
			const bool , const bool , const bool , 
			const char, const char , const char)), packetManager, 
			SLOT(doSendMessage(const int , const bool  , QString &, const char, 
			const bool , const bool , const bool , 
			const char , const char, const char)));	
	QObject::connect(windowList, SIGNAL(requestHistory(const int)), this, SLOT(slotRequestHistory(const int)));	
	QObject::connect(windowList, SIGNAL(requestBuddyQQShow(const int)), this, SLOT(slotRequestQQShow(const int)));	
	QObject::connect(windowList, SIGNAL(requestMyQQShow()), this, SLOT(slotRequestMyQQShow()));
	slotDoLogin();
}

void EvaMain::slotDoLogin()
{
	tray->setLoginWaiting();
	connecter->redirectTo(QQServer.toIPv4Address(), -1);
}

void EvaMain::slotDoCancel()
{
	if(loginWin->isVisible())
		loginWin->hide();
	if(!mainWin->isVisible())
		doQuit();
}

void EvaMain::slotConnectReady( )
{
	packetManager->doLogin();
}

void EvaMain::slotLoginOK( )
{
	QHostAddress addr;
	addr.setAddress(loginWin->getProxyIP());
	sysSetting->saveSetting(loginWin->getQQ(), loginWin->getMd5Password(),
					loginWin->isRememberChecked(), loginWin->isHiddenLoginMode(),  
					(int)loginWin->getConnectionType(),
					addr.toIPv4Address(), loginWin->getProxyPort(), loginWin->getProxyUserName(),
					loginWin->getProxyParam());
	initUserLeaveMenu();
	switch(user->getStatus()){
	case EvaUser::Eva_Online:
		mainWin->online();
		tray->setOnline();
		break;
	case EvaUser::Eva_Offline:
		mainWin->offline();
		tray->setOffline();
		break;
	case EvaUser::Eva_Leave:
		mainWin->leave();
		tray->setLeave();
		break;
	case EvaUser::Eva_Invisible:
		mainWin->invisible();
		tray->setInvisible();
	}

	if(!user->isBuddiesLoaded())
		packetManager->doGetUserInfo(user->getQQ());
		
	loggedIn = true;
	QTimer::singleShot(5000,this, SLOT(slotGetOnlineStatus()));
}

void EvaMain::slotOfflineReady()
{ 
	mainWin->offline();
	tray->setOffline();
	loggedIn = false;
}

void EvaMain::slotOnlineReady( )
{
	mainWin->online();
	tray->setOnline();
}

void EvaMain::slotInvisibleReady( )
{
	mainWin->invisible();
	tray->setInvisible();
}

void EvaMain::slotLeaveReady( )
{
	mainWin->leave();
	tray->setLeave();
}

void EvaMain::slotNetworkException( int exp)
{
	printf("network exception -- number:%d\n", exp);
	mainWin->offline();
	tray->setOffline();
	packetManager->doLogout();
	QMessageBox::information(0, i18n("Network"), 
		i18n("Network error occurred, check your network then try Eva later please."));
}

void EvaMain::slotPacketException( int cmd)
{
	printf("packet exception -- commend code: 0x%4x\n", cmd);
	if(cmd == QQ_CMD_KEEP_ALIVE){
		if(numOfLostKeepAlivePackets <= 4 )
			numOfLostKeepAlivePackets++; 
			
	}
	if(cmd == QQ_CMD_LOGIN){
		mainWin->offline();
		tray->setOffline();
		packetManager->doLogout();
		QMessageBox::information(0, i18n("Eva Login"), 
			i18n("Cannot login, try later please."));
	}
	
	if(numOfLostKeepAlivePackets>4){
		mainWin->offline();
		tray->setOffline();
		packetManager->doLogout();
		QMessageBox::information(0, i18n("Eva Connection"), 
			i18n("Lost connection with server, try later please."));
	}
}

void EvaMain::slotWrongPassword( )
{
	QMessageBox::information(0, i18n("Eva Login"), 
			i18n("Password is incorrect."));
}

void EvaMain::slotFriendListReady( )
{
	std::list<QQFriend>::iterator iter;
	std::list<QQFriend> list = (user->getFriendList()).getAllFriends();
	for(iter = list.begin(); iter != list.end(); ++iter){
		QString nick = codec->toUnicode(iter->getNick().c_str());
		int faceID = (int)((unsigned char)(iter->getFace())/3) + 1;
		QPixmap *p = images->getFace(faceID, true);
		QPixmap *poff = images->getFace(faceID, false);	
		mainWin->setFaceSize(global->getFaceSize());			
		mainWin->addBuddy(nick, iter->getQQ(), iter->getGroupIndex(), p, poff);
	}

	if(!user->isBuddiesLoaded()){
		user->saveGroupedBuddyList();
		user->setBuddyLoadedEnabled(true);
	}
	if(user->getSetting()->isShowOnlineEnabled())
		mainWin->slotShowOnlineBuddies();
	else
		mainWin->slotShowAllBuddies();
	if(!onlineFriendTimer->isActive())
		onlineFriendTimer->start(60000, false);
}

void EvaMain::slotFriendStatusChanged( int id )
{
	const QQFriend *frd = (user->getFriendList()).getFriend(id);
	if(frd){
		switch(frd->getStatus()){
		case QQ_FRIEND_STATUS_ONLINE:
			mainWin->changeToOnline(id);
			if(user->getSetting()->isShowBudyOnlineNotifyEnabled()){
				EvaTipWindow *tip = new EvaTipWindow(images, codec->toUnicode(frd->getNick().c_str()), 
									id, frd->getFace(), i18n("I am online."));
				QObject::connect(tip, SIGNAL(requestChat(const int)), SLOT(slotRequestChat(const int)));
			}
			break;
		case QQ_FRIEND_STATUS_OFFLINE:
			mainWin->changeToOffline(id);
			break;
		case QQ_FRIEND_STATUS_LEAVE:
			mainWin->changeToLeave(id);
			if(user->getSetting()->isShowBudyOnlineNotifyEnabled()){
				EvaTipWindow *tip = new EvaTipWindow(images, codec->toUnicode(frd->getNick().c_str()), 
									id, frd->getFace(), i18n("I am busy ..."));
				QObject::connect(tip, SIGNAL(requestChat(const int)), SLOT(slotRequestChat(const int)));
			}
			break;
		case QQ_FRIEND_STATUS_INVISIBLE:
			mainWin->changeToInvisible(id);
			break;
		}
	}else{
		printf("buddy %d not in list\n", id);
	}
}

void EvaMain::slotTxtMessage(int sender, bool, QString message, QDateTime, const char, 
			const bool, const bool, const bool, 
			const char, const char, const char)
{
	QString reply="";
	if(user->getStatus() == EvaUser::Eva_Leave && user->getSetting()->isAutoReplyEnabled()){
		reply = user->getSetting()->getSelectedAutoReply();
		packetManager->doSendMessage(sender, false, reply, 9, false, false, false, 0,0,0);
	}
	if(!(windowList && windowList->isChatWindowExisted(sender))){	
		mainWin->newMessage(sender);
		const QQFriend *frd = (user->getFriendList()).getFriend(sender);
		char faceId = 0x00;
		if(frd)
			faceId = frd->getFace();
		tray->newTxtMessage(sender, faceId);
		if(user->getSetting()->isShowMessageTipEnabled()){
			EvaTipWindow *tip = new EvaTipWindow(images, codec->toUnicode(frd->getNick().c_str()), sender, faceId, message);
			QObject::connect(tip, SIGNAL(requestChat(const int)), SLOT(slotRequestChat(const int)));
		}
	}
	if(user->getSetting()->isSoundEnabled())
		global->getSoundResource()->playNewMessage();
}

void EvaMain::slotFriendGroupsReady( )
{
	mainWin->clearList();
	initGroups();
	slotFriendListReady();
	std::list<QQFriend>::iterator iter;
	std::list<QQFriend> list = (user->getFriendList()).getAllFriends();
	for(iter = list.begin(); iter != list.end(); ++iter){
		mainWin->changeGroupTo(iter->getQQ(), iter->getGroupIndex());
	}
	if(!user->isBuddiesLoaded()){
		user->saveGroupedBuddyList();
		user->setBuddyLoadedEnabled(true);
	}
	std::list<int>msgs = windowList->getMessages();
	std::list<int>::iterator itr;
	for(itr = msgs.begin(); itr != msgs.end(); ++itr){
		mainWin->newMessage(*itr);
	}
}

void EvaMain::slotDoOnline()
{
	if(user->getStatus() == EvaUser::Eva_Offline){
		user->setStatus(EvaUser::Eva_Online);
		slotDoLogin();
	}else
		packetManager->doChangeStatus(EvaUser::Eva_Online);
}

void EvaMain::slotDoOffline()
{
	packetManager->doChangeStatus(EvaUser::Eva_Offline);
}

void EvaMain::slotDoLeave()
{
	if(user->getStatus() == EvaUser::Eva_Offline){
		user->setStatus(EvaUser::Eva_Leave);
		slotDoLogin();
	}else
		packetManager->doChangeStatus(EvaUser::Eva_Leave);
}

void EvaMain::slotDoInvisible()
{
	if(user->getStatus() == EvaUser::Eva_Offline){
		user->setStatus(EvaUser::Eva_Invisible);
		slotDoLogin();
	}else
		packetManager->doChangeStatus(EvaUser::Eva_Invisible);
}

void EvaMain::slotDoLogout()
{
	packetManager->doLogout();
	loggedIn = false;
}

void EvaMain::slotDoDownloadGroups()
{
	user->setBuddyLoadedEnabled(false);
	packetManager->doGetGroups();
}

void EvaMain::slotDoUploadGroups()
{
	packetManager->doUploadGroups();
}

void EvaMain::slotFriendGroupsUploadReady(bool ok)
{
	if(ok)
		QMessageBox::information(mainWin, i18n("Eva Upload Groups"), 
				i18n("Uploading grouped friends successfully."));
	else
		QMessageBox::information(mainWin, i18n("Eva Upload Groups"), 
				i18n("Uploading grouped friends failed."));
}

void EvaMain::slotDoDownloadBuddies()
{
	user->setBuddyLoadedEnabled(false);	
	packetManager->doGetAllFriends();
}

void EvaMain::slotDoChangeUser()
{
	if(!loginWin->isVisible())
		loginWin->show();
}

void EvaMain::slotGroupDeleted( const int index)
{
	user->removeGroupName(index);
	user->saveGroupedBuddyList();
}

void EvaMain::slotGroupAdded( QString gn, int index)
{
	std::string name = (codec->fromUnicode(gn)).data();
	user->newGroup(name);
	int newIndex = user->getGroupIndexOf(name);
	mainWin->listView->findGroup(index)->setGroupIndex(newIndex);
	user->saveGroupedBuddyList();
}

void EvaMain::slotGroupRenamed( QString gn, int index)
{
	std::string name = (codec->fromUnicode(gn)).data();
	user->updateGroupName(name, index);
	user->saveGroupedBuddyList();
}

void EvaMain::slotGroupChanged(int id, int index)
{
	user->getFriendList().updateFriendGroupIndex(id, index);
	user->saveGroupedBuddyList();
}

void EvaMain::slotRequestDetails(const int id)
{	
	QStringList details;
	details.append(QString::number(id));
	
	const QQFriend *frd = (user->getFriendList()).getFriend(id); 
	if(frd){
		std::string qq = frd->getUserInformation().at(0);
		if(qq!="-")
			details = packetManager->convertDetails(frd->getUserInformation());
	}
		
	EvaDetailsWindow *detailWin;
	if(id == user->getQQ()){
		if(user->getDetails().at(0)!="-")
			details = packetManager->convertDetails(user->getDetails());
		detailWin = new EvaDetailsWindow(details,true);
		QObject::connect(detailWin, SIGNAL(requestModify(QStringList, QString, QString)), 
					packetManager, SLOT(doModifyDetails(QStringList, QString, QString)));	
		QObject::connect(packetManager, SIGNAL(modifyInfo(bool)), 
					detailWin, SLOT(slotUpdateResult(bool)));
	}else{
		detailWin = new EvaDetailsWindow(details,false);
	}	
	QObject::connect(detailWin, SIGNAL(requestUpdate(const int)), packetManager, SLOT(doGetUserInfo(const int)));
	QObject::connect(detailWin, SIGNAL(requestQQshow(const int)), this, SLOT(slotRequestQQShow(const int)));
	QObject::connect(packetManager, SIGNAL(userInfoReady(QStringList)), detailWin, SLOT(slotDetailsUpdated(QStringList)));	
	QObject::connect(images, SIGNAL(qqShowReady(const int)), detailWin, SLOT(slotBuddyQQShowReady(const int)));	
	detailWin->show();
}

void EvaMain::slotRequestChat(const int id)
{
	const QQFriend *frd = user->getFriendList().getFriend(id);
	mainWin->gotMessage(id);
	tray->gotTxtMessage(id);
	windowList->openChatWindow(frd);
}

void EvaMain::slotRequestHistory(const int id)
{
	QString nick = codec->toUnicode(user->getFriendList().getFriend(id)->getNick().c_str());
	
	EvaChatWindow *win = windowList->getWindow(id);
	EvaHistoryViewer *viewer = new EvaHistoryViewer(id, nick, user->getSetting());
	
	int faceId = atoi(user->getDetails().at(ContactInfo::Info_face).c_str());
	QPixmap *face = images->getFace(images->getFaceFileIndex(faceId));
	viewer->setIcon(*face);
	
	if(win){
		QObject::connect(viewer, SIGNAL(historyDoubleClicked(int, QString, int, QString, bool,
					 QString, QDateTime, const char, 
					const bool, const bool, const bool, 
					const char, const char, const char)), 
				win, 
				SLOT(slotAddMessage(int, QString, int, QString, bool,
					 QString, QDateTime, const char, 
					const bool, const bool, const bool, 
					const char, const char, const char)));
		viewer->move(win->x(), win->y() + win->height() + 25);
	}else{
		QRect scr = KApplication::desktop()->screenGeometry();    
		viewer->move(scr.center() - viewer->rect().center());
	}
	viewer->show();
}

void EvaMain::slotRequestQQShow(const int id)
{
	images->requestQQShow(id);
}

void EvaMain::slotRequestMyQQShow()
{
	slotRequestQQShow(user->getQQ());
}

void EvaMain::slotQQShowReady( const int id)
{
	if(id == user->getQQ())
		windowList->slotMyQQShowReady();
	else
		windowList->slotBuddyQQShowReady(id);
}

void EvaMain::slotRequestSearch( )
{
	EvaSearchWindow *win = new EvaSearchWindow(images, packetManager->getNumOnlineUsers(), 0, "Searching");
	QObject::connect(win, SIGNAL(requestSearchUsers(const bool, const QString, const QString, const QString, const QString, const bool)),
			 packetManager, 
			 SLOT(doSearchUsers(const bool, const QString, const QString, const QString, const QString, const bool)));
	QObject::connect(win, SIGNAL(requestUserInfo(const int)), this, SLOT(slotRequestDetails(const int)));
	QObject::connect(win, SIGNAL(requestAddAuthBuddy(const int, const QString &)), 
			packetManager, 
			SLOT(doAddAuthBuddy(const int , const QString &)));
	QObject::connect(win, SIGNAL(requestAddBuddy(const int)), packetManager, SLOT(doAddBuddy(const int)));
	
	QObject::connect(packetManager, SIGNAL(searchUsersReady(const bool, const std::list<OnlineUser>)), win, 
			SLOT(slotSearchUsersReady(const bool, const std::list<OnlineUser>)));
	QObject::connect(packetManager, SIGNAL(addBuddyReady()), win, SLOT(slotAddBuddyReady()));
	QObject::connect(packetManager, SIGNAL(addBuddyRejected()), win, SLOT(slotAddBuddyRejected()));
	QObject::connect(packetManager, SIGNAL(addBuddyNeedAuth()), win, SLOT(slotBuddyNeedAuth()));
	QObject::connect(packetManager, SIGNAL(addBuddySentToServer(bool)), win, SLOT(slotAddBuddySentToServer(bool)));
	QRect scr = KApplication::desktop()->screenGeometry();    
	win->move(scr.center() - win->rect().center());	
	win->show();
}

void EvaMain::slotSystemMeBeenAdded(int)
{
	if(user->getSetting()->isSoundEnabled())
		global->getSoundResource()->playSysMessage();
}

void EvaMain::slotSystemAddMeRequest(int, QString)
{
	if(user->getSetting()->isSoundEnabled())
		global->getSoundResource()->playSysMessage();
}

void EvaMain::slotSystemAddRequestApproved(int)
{
	if(user->getSetting()->isSoundEnabled())
		global->getSoundResource()->playSysMessage();
}

void EvaMain::slotSystemAddRequestRejected(int, QString)
{
	if(user->getSetting()->isSoundEnabled())
		global->getSoundResource()->playSysMessage();
}

void EvaMain::slotRequestSystemMessage( )
{
	EvaUserSetting::sysMessage m = user->getSetting()->getLastSysMessage();
	if(m.type == 0 && m.from == 0) return;
	slotShowSystemMessage( m.type, m.from, m.to, m.message);
}

void EvaMain::slotShowSystemMessage(const uint8_t type, const int from, const int, const QString message)
{	
	EvaNotifyWindow *win = new EvaNotifyWindow(0);
	switch(type){
	case 200:
		win->slotAddBuddy(from);
	case QQ_MSG_SYS_BEING_ADDED:
		win->slotMeBeenAdded( from);
		break;       
	case QQ_MSG_SYS_ADD_FRIEND_REQUEST:
		win->slotAddMeRequest(from, message);
		break;
	case QQ_MSG_SYS_ADD_FRIEND_APPROVED:
		win->slotAddRequestApproved(from);
		break;
	case QQ_MSG_SYS_ADD_FRIEND_REJECTED:
		win->slotAddRequestRejected(from, message);
		break;
	default:
		if(user->getSetting()->isShowSystemBroadcastEnabled())
			win->slotOtherNotification(from, message);
	}
	QObject::connect(win, SIGNAL(requestUserInfo(const int)), this, SLOT(slotRequestDetails(const int)));
	QObject::connect(win, SIGNAL(requestAddAuthBuddy(const int, const QString &)), 
			packetManager, SLOT(doAddAuthBuddy(const int, const QString &)));
	QObject::connect(win, SIGNAL(requestAddBuddy(const int)), packetManager, SLOT(doAddBuddy(const int)));
	QObject::connect(win, SIGNAL(requestApproveBuddy(const int)), packetManager, SLOT(doApproveBuddy(const int)));
	QObject::connect(win, SIGNAL(requestRejectBuddy(const int, const QString &)), 
			packetManager, SLOT(doRejectBuddy(const int, const QString &)));
	
	QObject::connect(packetManager, SIGNAL(addBuddyReady()), win, SLOT(slotAddBuddyReady()));
	QObject::connect(packetManager, SIGNAL(addBuddyRejected()), win, SLOT(slotAddBuddyRejected()));
	QObject::connect(packetManager, SIGNAL(addBuddyNeedAuth()), win, SLOT(slotBuddyNeedAuth()));
	QObject::connect(packetManager, SIGNAL(addBuddySentToServer(bool)), win, SLOT(slotAddBuddySentToServer(bool)));
	
	QObject::connect(packetManager, SIGNAL(systemMeBeenAdded(int)), win, SLOT(slotMeBeenAdded(int)));
	QObject::connect(packetManager, SIGNAL(systemAddMeRequest(int, QString)), win, SLOT(slotAddMeRequest(int, QString)));
	QObject::connect(packetManager, SIGNAL(systemAddRequestApproved(int)), win, SLOT(slotAddRequestApproved(int)));
	QObject::connect(packetManager, SIGNAL(systemAddRequestRejected(int, QString)), win, SLOT(slotAddRequestRejected(int, QString)));
	
	if(user->getSetting()->isShowSystemBroadcastEnabled())
		QObject::connect(packetManager, SIGNAL(systemNotification(int, QString)), win, SLOT(slotOtherNotification(int, QString)));
	QRect scr = KApplication::desktop()->screenGeometry();    
	win->move(scr.center() - win->rect().center());
	win->show();
}


void EvaMain::slotRequestSystemMessages( )
{
	EvaSysHistoryViewer *viewer = new EvaSysHistoryViewer( user->getSetting());
	QObject::connect(viewer, SIGNAL(historyDoubleClicked(const uint8_t, const int, const int, const QString)), 
			SLOT(slotShowSystemMessage(const uint8_t, const int, const int, const QString)));
	
	QRect scr = KApplication::desktop()->screenGeometry();    
	viewer->move(scr.center() - viewer->rect().center());
	viewer->show();
}

void EvaMain::slotRequestDelete( const int id)
{
	packetManager->doDeleteBuddy(id);
}

void EvaMain::slotDeleteBuddyReady( int id, bool ok)
{
	if(ok)
		mainWin->deleteBuddy(id);
	else{
		QMessageBox::information(mainWin, i18n("Eva Delete Buddy"), 
				QString(i18n("Delete buddy \"%1\" failed.")).arg(id));
	}
}

void EvaMain::slotRequestSystemSettingWindow( )
{
	EvaSysSettingWindow *win = new EvaSysSettingWindow(images, user->getSetting(), mainWin);
	QRect scr = KApplication::desktop()->screenGeometry();    
	win->move(scr.center() - win->rect().center());	
	win->show();
}

void EvaMain::slotDeleteMeFrom( int id)
{
	if(deleteFromQQ != -1) return;  // make sure we only delete from one friend's list at a moment
	const QQFriend *frd = user->getFriendList().getFriend(id);
	if(!frd) return;
	QString nick = codec->toUnicode(frd->getNick().c_str());
	if(QMessageBox::warning( mainWin, i18n( "Eva Blacklist"),
		QString(i18n("put \"%1\" into Blacklist, are you sure?")).arg(nick), i18n( "Yes"),i18n( "No"), 0, 0, 1))
		return;
	deleteFromQQ = id;
	packetManager->doDeleteMeFrom(id);
}

void EvaMain::slotDeleteMeReply( bool ok)
{
	if(ok){
		mainWin->changeGroupTo(deleteFromQQ, user->getBlackIndex());
		deleteFromQQ = -1;
	}else
		QMessageBox::information(mainWin, i18n("Eva Blacklist"), 
			QString(i18n("Blacklist operation on \"%1\" failed.")).arg(deleteFromQQ));
}

void EvaMain::slotRequestAddBuddy( int id)
{
	if(QMessageBox::warning( mainWin, i18n( "Eva Add Buddy"),
		QString(i18n("add \"%1\" into your Buddy list?")).arg(id), i18n( "Yes"),i18n( "No"), 0, 0, 1))
		return;
		
	slotShowSystemMessage(200, id, id,"");
	//packetManager->doAddBuddy(id);
}

void EvaMain::slotMyInfoReady( )
{	
	QString myNick = codec->toUnicode(user->getDetails().at(ContactInfo::Info_nick).c_str()); 
	mainWin->setCaption(myNick + " - Eva");
	int myFaceId = atoi(user->getDetails().at(ContactInfo::Info_face).c_str());
	QPixmap *face = images->getFace(images->getFaceFileIndex(myFaceId));
	mainWin->setIcon(*face);
	mainWin->setMainInfo(user->getQQ(), myNick, face?face:images->getFace(0)); 
	windowList->setMyName(myNick, user->getQQ());
	
	if(!user->isBuddiesLoaded())
		slotDoDownloadBuddies();
}

