/***************************************************************************
 *   Copyright (C) 2005 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 "evalistview.h"
#include "evaqunlistview.h"
#include "evauser.h"
#include "../evamain.h"
#include "evaresource.h"
#include "evaipseeker.h"
#include "evahtmlparser.h"
#include "evaqtutil.h"
#include "evautil.h"
#include "evauhmanager.h"
#include <qheader.h>
#include <qpixmap.h>
#include <qimage.h>
#include <qtimer.h>
#include <qdragobject.h>
#include <qtextcodec.h>
#include <qpoint.h>
#include <qrect.h>
#include <qtooltip.h>
#include <klocale.h>

EvaToolTip::EvaToolTip(QListView *listView, QToolTipGroup *group)
	: QToolTip(static_cast<QWidget *>(listView->viewport()), group),
	mListView(listView)
{
	//setPalette( QPalette(Qt::yellow, QColor(20,190,255)));
}

EvaToolTip::~EvaToolTip()
{
}

void EvaToolTip::maybeTip(const QPoint &p)
{
	QListViewItem *item = dynamic_cast<QListViewItem *>(mListView->itemAt(p));
	if(!item) return;
	int section = mListView->header()->sectionAt(p.x());
	QRect itemRect = mListView->itemRect(item);
	QRect headerRect = mListView->header()->sectionRect(section);
	QRect destRect(headerRect.left(), itemRect.top(), headerRect.width(), itemRect.height());
	
	EvaBuddyItem *buddy = dynamic_cast<EvaBuddyItem *>(mListView->itemAt(p));
	if(buddy){
		switch(section){
		case 0:
			tip(destRect, buddy->tip());
			break;
		default:
			tip(destRect, i18n("Double click to chat"));
			break;
		}
	}else{
		EvaGroupItem *group = dynamic_cast<EvaGroupItem *>(mListView->itemAt(p));
		if(group){
			switch(section){
			case 0:
				tip(destRect, group->tip());
				break;
			default:
				tip(destRect, i18n("Click to display all members"));
				break;
			}		
		}else{
			EvaQunItem *qun = dynamic_cast<EvaQunItem *>(mListView->itemAt(p));
			if(qun){
				switch(section){
				case 0:
					tip(destRect, qun->tip());
					break;
				default:
					tip(destRect, i18n("Double click to chat"));
					break;
				}
			}else{
				EvaQunBuddyItem *qunBuddy = dynamic_cast<EvaQunBuddyItem *>(mListView->itemAt(p));
				if(qunBuddy){
					switch(section){
					case 1:
						tip(destRect, qunBuddy->tip());
						break;
					default:
						tip(destRect, i18n("Right click to see more"));
						break;
					}
				}
			}
		}
	}
	
}

QPixmap *EvaBuddyItem::pixNA =0; 
QPixmap *EvaBuddyItem::pixMsg =0; 
QSize EvaBuddyItem::faceSize = QSize(16, 16); 

EvaBuddyItem::EvaBuddyItem( QListViewItem *parent, const QString &nick, const int id, const QString signature,
			QPixmap *on, QPixmap *off, EvaBuddyItem::Status s )
		: QListViewItem( parent, " "+nick), 
		status(s),
		pixOnline(on), pixOffline(off),nickName(nick), mSignature(signature), qqNum(id),
		numOfMessages(0), isMsgShown(false)
{
	setDragEnabled(true);
	updateText();
	refreshFace(true);
	timer = new QTimer();
	QObject::connect(timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
}

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

void EvaBuddyItem::updateNick(const QString &nick)
{
	nickName = nick;
	updateText();
}

void EvaBuddyItem::updateSignature(const QString &sig)
{
	mSignature = sig;
	updateText();
}

void EvaBuddyItem::updateText()
{
	QString showName = " " + nickName;
	if(!mSignature.isEmpty())
		showName += " [" + mSignature + "]";
	setText(0, showName);
}

void EvaBuddyItem::updateFacePixmaps(QPixmap *on, QPixmap *off)
{
	if(on)
		pixOnline = on;
	if(off)
		pixOffline = off;
	refreshFace(true);
}

const QPixmap *EvaBuddyItem::pixmapOnline() const { return pixOnline; }
const QPixmap *EvaBuddyItem::pixmapOffline() const { return pixOffline; }

QPixmap *EvaBuddyItem::pixmapNA() { return pixNA; }
void EvaBuddyItem::setPixmapNA(QPixmap *p) { pixNA = p; }
QPixmap *EvaBuddyItem::pixmapMsg() { return pixMsg; }
void EvaBuddyItem::setPixmapMsg(QPixmap *p) { pixMsg = p; }

const int EvaBuddyItem::getQQ() const { return qqNum; }
const EvaBuddyItem::Status EvaBuddyItem::getStatus() const { return status; }
const int EvaBuddyItem::numOfUnreadMsgs() const { return numOfMessages; }

const bool EvaBuddyItem::hasMessages() const
{
	if(timer->isActive())
		return true;
	return false;
}

void EvaBuddyItem::refreshFace(bool isForcedToChange)
{
	switch(status){
	case Online:
		slotChangeToOnline(isForcedToChange);
		break;
	case Offline:
		slotChangeToOffline(isForcedToChange);
		break;
	case Leave:
		slotChangeToLeave(isForcedToChange);
		break;
	case Invisible:
		slotChangeToInvisible(isForcedToChange);
		break;
	default:
		slotChangeToOffline(isForcedToChange);
	}
}

QString EvaBuddyItem::tip()
{
	const QQFriend *frd = (EvaMain::user->getFriendList()).getFriend(qqNum); 
	QString tip = "<qt>";
	if(frd){
		EvaIPSeeker ipAddr(EvaGlobal::getDirPath().latin1());
		QTextCodec *codec = QTextCodec::codecForName("GB18030");
		QString addr = codec->toUnicode(ipAddr.getIPLocation(frd->getIP()).c_str());
		if(addr.length()<4) addr = "0.0.0.0";
		
		QString htmlName = nickName;
		EvaHtmlParser parser;
		parser.setAbsImagePath(EvaMain::images->getSmileyPath());
		parser.convertToHtml(htmlName, false, true);
		QString signature = codec->toUnicode(frd->getSignature().c_str());
		if(signature.length() > 40)
			signature = signature.left(37) + "...";
		if(!signature.isEmpty())
			signature = "[" + signature + "]";
		QString facePath = "<img src=\"" + EvaMain::images->getFacePath() + "/" +
				QString::number(EvaMain::images->getFaceFileIndex(frd->getFace())) + 
				".png\"></img>";
		if(frd->hasUserHead() && EvaMain::uhManager){
			QString uhFileName = EvaMain::uhManager->getFileName(frd->getQQ());
			if(!uhFileName.isEmpty())
				facePath = "<img src=\"" + uhFileName + "\"></img>";
		}
		int suns, moons, stars;
		EvaUtil::calcSuns(frd->getLevel(), &suns, &moons, &stars);
		QString strSun =  "<img src=\"" + EvaMain::images->getIconFullPath("TIME_SUN") + "\"></img>";
		QString strMoon = "<img src=\"" + EvaMain::images->getIconFullPath("TIME_MOON") + "\"></img>";
		QString strStar = "<img src=\"" + EvaMain::images->getIconFullPath("TIME_STAR") + "\"></img>";
		QString level;
		for(int i=0; i<suns; i++){
			level += strSun;
		}
		for(int i=0; i<moons; i++){
			level += strMoon;
		}
		for(int i=0; i<stars; i++){
			level += strStar;
		}
		
		tip += "<table width = 200><tr><td width=50 align = center valign = middle>" + facePath + 
			"</td><td align = left valign = middle><b><font color = blue>"+
			i18n("QQ") +": </font></b>"+ QString::number(qqNum) +"<br><b><font color = blue>"+
			i18n("Nickname:") + " </font></b>"+htmlName +"<br>"+ signature + "<br><b><font color = blue>"+ 
			i18n("Level") +": </font></b>"+ level + "  (" + QString::number(frd->getLevel()) +")<br><b><font color = blue>"+
			i18n("IP:") +" </font></b>"+ addr + "</td></tr></table>";
	} else
		tip += "<b><font color = blue>" + 
			i18n("QQ") +": </font></b><br>"+ QString::number(qqNum) +
			i18n("Nickname:") +" </font></b>"+ nickName +"<br><b><font color = blue>";
	tip += "</qt>";
	return tip;
}

void EvaBuddyItem::slotChangeToOnline(bool isForcedToChange)
{
	if(!isForcedToChange && status == Online) return;
	status = Online;
	if(!pixOnline) return ;
	runScaleImageThread(pixOnline);
	//updateFace(pixOnline);

}

void EvaBuddyItem::slotChangeToLeave(bool isForcedToChange)
{
	if(!isForcedToChange && status == Leave) return;
	status = Leave;
	if(!pixOnline) return;
	QPixmap *leave = new QPixmap(*pixOnline);
	copyBlt(leave, leave->width() - pixNA->width(), leave->height()- pixNA->height(), 
		pixNA, 0, 0, pixNA->width(), pixNA->height());
		
	runScaleImageThread(leave);
	//updateFace(leave);
	delete leave;
}

void EvaBuddyItem::slotChangeToOffline(bool isForcedToChange)
{
	if(!isForcedToChange && status == Offline) return;
	status = Offline;
	if(!pixOffline) return ;
	runScaleImageThread(pixOffline);
	//updateFace(pixOffline);
}

void EvaBuddyItem::slotChangeToInvisible(bool isForcedToChange)
{
	slotChangeToOffline(isForcedToChange);   
}

void EvaBuddyItem::slotStartFlash()
{
	if(!pixMsg) return; 
	setPixmap(1,*pixMsg);
	isMsgShown = true;
	if(!timer->isActive())
		timer->start(500, false);
	
}

void EvaBuddyItem::slotStopFlash()
{
	if(timer->isActive())
		timer->stop();
	setPixmap(1,0);
	isMsgShown = false;
}

void EvaBuddyItem::runScaleImageThread(QPixmap *p)
{
	if(!p) return;
	//printf("come\n");
	EvaMain::helper->setCategory(EvaHelper::ScaleImage,this);
	EvaMain::helper->setScaleArgs(*p, faceSize);
	EvaMain::helper->run();
}

void EvaBuddyItem::customEvent( QCustomEvent *e)
{
	if(e->type() == EvaScaleImageEvent){
		EvaScaleEvent *se = (EvaScaleEvent *)e;
		QPixmap p = se->pixmap();
		updateFace(&p);
	}
}

void EvaBuddyItem::updateFace(QPixmap *pix)
{
	if(!pix) return;
	//QImage img(pix->convertToImage().smoothScale(faceSize));
	//QPixmap p(img);
	setPixmap(0, *pix);
}

QString EvaBuddyItem::key( int, bool ) const
{
	QString prefix="";
	switch(status){
	case Online:
		prefix = "0";
		break;
	case Leave:
		prefix = "1";
		break;
	case Invisible:
		prefix = "2";
		break;
	case Offline:
	default: 
		prefix = "3";
	}
	if(timer->isActive()) prefix+="0";
	return prefix + nickName;
}

void EvaBuddyItem::slotTimeout()
{
	if(!pixMsg) return ;
	if(isMsgShown){
		setPixmap(1,0);
		isMsgShown = false;
	}else{
		setPixmap(1,*pixMsg);
		isMsgShown = true;
	}
}

/* ---------------------------------------------------------------------------------       */

QPixmap *EvaGroupItem::pixOpened = 0;
QPixmap *EvaGroupItem::pixClosed = 0;
QPixmap *EvaGroupItem::pixMsg =0; 

EvaGroupItem::EvaGroupItem(QListView *parent, const QString &name, int index)
		: QListViewItem( parent, " " + name),
		groupName(name), groupIndex(index), isMsgShown(false),
		numOnlineFriends(0), type(Normal)
{
	if(pixClosed) setPixmap(0, *pixClosed);
	timer = new QTimer();
	QObject::connect(timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
}

EvaGroupItem::EvaGroupItem(QListViewItem *parent, const QString &name, Type t)
		: QListViewItem( parent, " " + name),
		groupName(name), groupIndex(-1), isMsgShown(false),
		numOnlineFriends(0), type(t)
{
	if(pixClosed) setPixmap(0, *pixClosed);
	timer = new QTimer();
	QObject::connect(timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
}

void EvaGroupItem::setOpen(bool o)
{
	if(o){
		if(pixOpened) setPixmap(0, *pixOpened);
	}else{
		if(pixClosed) setPixmap(0, *pixClosed);
	}
	QListViewItem::setOpen(o);
}

const int EvaGroupItem::getGroupIndex() const { return groupIndex;}
const QString &EvaGroupItem::getGroupName() const { return groupName; }
void EvaGroupItem::setPixmapOpen(QPixmap *p) { pixOpened = p ;}
void EvaGroupItem::setPixmapClose(QPixmap *p) { pixClosed = p ;}
void EvaGroupItem::setPixmapMsg(QPixmap *p) { pixMsg = p; }

QPixmap *EvaGroupItem::pixmapOpen() { return pixOpened; }
QPixmap *EvaGroupItem::pixmapClose() { return pixClosed; }
QPixmap *EvaGroupItem::pixmapMsg() { return pixMsg; }

void EvaGroupItem::setGroupName(const QString name)
{
	groupName = name;
	setText(0, " " + groupName);
}

void EvaGroupItem::addBuddy(EvaBuddyItem *item)
{
	insertItem(item);
	updateGroupTitle();
}

EvaBuddyItem * EvaGroupItem::addBuddy(const QString &nick, const int id, const QString signature, QPixmap *on, 
				QPixmap *off, EvaBuddyItem::Status status )
{
	EvaBuddyItem *buddy = new EvaBuddyItem(this, nick, id, signature, on, off, status);
	updateGroupTitle();
	return buddy;
}

void EvaGroupItem::updateNick(const int id, const QString &nick)
{
	EvaBuddyItem *item = findBuddy(id);
	if(item)
		item->updateNick(nick);
}

void EvaGroupItem::updateSignature(const int id, const QString &sig)
{
	EvaBuddyItem *item = findBuddy(id);
	if(item)
		item->updateSignature(sig);
}

void EvaGroupItem::updateFacePixmaps(const int id, QPixmap *on, QPixmap *off)
{
	EvaBuddyItem *item = findBuddy(id);
	if(item)
		item->updateFacePixmaps(on, off);
}

const bool EvaGroupItem::removeBuddy(const int id)
{
	EvaBuddyItem *item = findBuddy(id);
	if(item){
		delete item;
		updateGroupTitle();
		return true;
	}
	return false;
}

EvaBuddyItem *EvaGroupItem::takeBuddy(const int id)
{
	EvaBuddyItem *item = findBuddy(id);
	if(item) takeItem(item);
	updateGroupTitle();
	return item;
}

const EvaBuddyItem *EvaGroupItem::getBuddy(const int id)
{
	return findBuddy(id);
}

bool EvaGroupItem::changeToOnline(const int id)
{
	EvaBuddyItem *item = findBuddy(id);
	if(item){
		if(item->getStatus() == EvaBuddyItem::Offline || item->getStatus() == EvaBuddyItem::Invisible) {
			numOnlineFriends++;
			updateGroupTitle();
		}
		item->slotChangeToOnline();
		item->setVisible(true);
		sort();
		return true;
	}
	return false;
}

bool EvaGroupItem::changeToLeave(const int id)
{
	EvaBuddyItem *item = findBuddy(id);
	if(item){
		if(item->getStatus() == EvaBuddyItem::Offline || item->getStatus() == EvaBuddyItem::Invisible) {
			numOnlineFriends++;
			updateGroupTitle();
		}
		item->slotChangeToLeave();
		item->setVisible(true);
		sort();
		return true;
	}
	return false;
}

bool EvaGroupItem::changeToOffline(const int id)
{
	EvaBuddyItem *item = findBuddy(id);
	if(item){
		if(item->getStatus() == EvaBuddyItem::Online || item->getStatus() == EvaBuddyItem::Leave) {
			numOnlineFriends--;
			updateGroupTitle();
		}
		item->slotChangeToOffline();
		sort();
		return true;
	}
	return false;
}

bool EvaGroupItem::changeToInvisible(const int id)
{
	EvaBuddyItem *item = findBuddy(id);
	if(item){
		if(item->getStatus() == EvaBuddyItem::Online || item->getStatus() == EvaBuddyItem::Leave) {
			numOnlineFriends--;
			updateGroupTitle();
		}
		item->slotChangeToInvisible();
		sort();
		return true;
	}
	return false;
}

bool EvaGroupItem::startFlash(const int id)
{
	EvaBuddyItem *item = findBuddy(id);
	if(item){
		item->setVisible(true);
		item->slotStartFlash();
		sort();
		isMsgShown = true;
		setPixmap(1,*pixMsg);
		QString note = QString(tr(" %1")).arg(messagsCount());
		setText(1, note);
		if(!timer->isActive())
			timer->start(500, false);
		return true;
	}else{
		EvaQunItem *qItem = findQun(id);
		if(qItem){
			qItem->setVisible(true);
			qItem->slotStartFlash();
			sort();
			isMsgShown = true;
			setPixmap(1,*pixMsg);
			QString note = QString(tr(" %1")).arg(messagsCount());
			setText(1, note);
			if(!timer->isActive())
				timer->start(500, false);
			return true;
		}
	}
	return false;
}

bool EvaGroupItem::stopFlash(const int id)
{	
	EvaBuddyItem *item = findBuddy(id);
	if(item){
		item->slotStopFlash();
		sort();
		int numMsgs = messagsCount();	
		QString note;	
		if(!numMsgs){
			if(timer->isActive())
				timer->stop();
			setText(1, "");
			setPixmap(1, 0);
			isMsgShown = false;
		}		
		return true;
	}else{
		EvaQunItem *qItem = findQun(id);
		if(qItem){
			qItem->slotStopFlash();
			sort();
			int numMsgs = messagsCount();
			QString note;	
			if(!numMsgs){
				if(timer->isActive())
					timer->stop();
				setText(1, "");
				setPixmap(1, 0);
				isMsgShown = false;
			}		
			return true;
		}
		
	}
	return false;
}

void EvaGroupItem::showAll()
{
	EvaBuddyItem *item = dynamic_cast<EvaBuddyItem *>(firstChild());
	while(item){
		if(!item->isVisible()) item->setVisible(true);
		item = dynamic_cast<EvaBuddyItem *>(item->nextSibling());
	}
}

void EvaGroupItem::showOnlineOnly()
{
	EvaBuddyItem *item = dynamic_cast<EvaBuddyItem *>(firstChild());
	EvaBuddyItem::Status s;
	while(item){
		s = item->getStatus();
		if(s==EvaBuddyItem::Online || s==EvaBuddyItem::Leave)
			item->setVisible(true);
		else
			item->setVisible(false);
		item = dynamic_cast<EvaBuddyItem *>(item->nextSibling());
	}
}

void EvaGroupItem::refreshFace()
{
	EvaBuddyItem *item = dynamic_cast<EvaBuddyItem *>(firstChild());
	while(item){
		item->refreshFace();
		item = dynamic_cast<EvaBuddyItem *>(item->nextSibling());
	}
}

const int EvaGroupItem::countOnlineFriends()
{
	EvaBuddyItem *item = dynamic_cast<EvaBuddyItem *>(firstChild());
	EvaBuddyItem::Status s;
	numOnlineFriends = 0;
	while(item){
		s = item->getStatus();
		if(s==EvaBuddyItem::Online || s==EvaBuddyItem::Leave)
			numOnlineFriends++;
		item = dynamic_cast<EvaBuddyItem *>(item->nextSibling());
	}
	return numOnlineFriends;
}

void EvaGroupItem::updateGroupTitle()
{
	sort();
	int num = countOnlineFriends();
	setText(0, " " + groupName + " (" + QString::number(num) + "/" + 
		QString::number(childCount()) + ")");
}

void EvaGroupItem::addQun(EvaQunItem *item)
{
	insertItem(item);
	updateGroupTitle();
}

void EvaGroupItem::addQun(QString name, const int id, QPixmap *pic )
{
	EvaQunItem *q = findQun(id);
	if(!q)
		new EvaQunItem(this, name, id, pic);
	else
		updateQun(name,id, pic);
	updateGroupTitle();
}

void EvaGroupItem::updateQun(QString name, const int id, QPixmap *pic)
{
	EvaQunItem *item = dynamic_cast<EvaQunItem *>(firstChild());
	while(item){
		if(item->getQunID() == id){
			item->setQunName(name);
			item->setQunPix(pic);
			break;
		}
		item = dynamic_cast<EvaQunItem *>(item->nextSibling());
	}	
}

bool EvaGroupItem::removeQun( const int id )
{
	EvaQunItem *item = findQun(id);
	if(item){
		takeItem(item);
		delete item;
		updateGroupTitle();
		return true;
	}
	return false;
}

bool EvaGroupItem::clearQunGroup()
{
	if(groupIndex != EvaUser::getQunIndex()) return false;
	EvaQunItem *item = dynamic_cast<EvaQunItem *>(firstChild());
	EvaQunItem *tmp;
	while(item){
		tmp = item;
		item = dynamic_cast<EvaQunItem *>(item->nextSibling());
		takeItem(tmp);
		delete tmp;
	}
	return true;
}

bool EvaGroupItem::hasQun( const int id )
{
	EvaQunItem *item = findQun(id);
	if(item) return true;
	else
		return false;
}

QString EvaGroupItem::tip()
{
	QString tip = "<table><tr><td align = left valign = middle><font color = red><b>"+
			i18n("Group") + ": </b></font>"+ groupName +"<br><b><font color = red>"+ 
			i18n("Members") +": </font></b>"+ QString::number(childCount()) +
			"</td></tr></table>";
	return tip;
}
	
void EvaGroupItem::okRename( int col )
{
	QListViewItem::okRename(col);
	groupName = text(0);
	setRenameEnabled( 0, false );
}

void EvaGroupItem::cancelRename( int col )
{
	QListViewItem::cancelRename(col);
	setRenameEnabled( 0, false );
}

QString EvaGroupItem::key( int, bool ) const
{
	QString sKey = "";
	if(groupIndex == 0)
		sKey = "A";
	else	if(groupIndex == EvaUser::getQunIndex())
			sKey = "Y";
		else	if(groupIndex == EvaUser::getAnonymousIndex() || groupIndex == EvaUser::getBlackIndex())
				sKey = "Z";
			else
				sKey = "B";
	return sKey + QString::number(groupIndex);
}

EvaBuddyItem *EvaGroupItem::findBuddy(const int id)
{
	EvaBuddyItem *item = dynamic_cast<EvaBuddyItem *>(firstChild());
	while(item){
		if(id == item->getQQ()){
			return item;
		}
		item = dynamic_cast<EvaBuddyItem *>(item->nextSibling());
	}
	return NULL;
}

EvaQunItem *EvaGroupItem::findQun(const int id)
{
	EvaQunItem *item = dynamic_cast<EvaQunItem *>(firstChild());
	while(item){
		if(id == item->getQunID()){
			return item;
		}
		item = dynamic_cast<EvaQunItem *>(item->nextSibling());
	}
	return NULL;
}

const int EvaGroupItem::messagsCount()
{
	int num = 0;
	EvaBuddyItem *item = dynamic_cast<EvaBuddyItem *>(firstChild());
	while(item){
		if(item->hasMessages())
			num++;
		item = dynamic_cast<EvaBuddyItem *>(item->nextSibling());
	}
	// it dosen't matter as group should has either all buddies or all quns
	EvaQunItem *qItem = dynamic_cast<EvaQunItem *>(firstChild());
	while(qItem){
		if(qItem->hasMessages())
			num++;
		qItem = dynamic_cast<EvaQunItem *>(qItem->nextSibling());
	} 
	return num;
}

void EvaGroupItem::slotTimeout()
{
	if(!pixMsg) return ;
	if(isMsgShown){
		setPixmap(1,0);
		setText(1, "");
		isMsgShown = false;
	}else{
		setPixmap(1,*pixMsg);
		QString note = QString(tr(" %1")).arg(messagsCount());
		setText(1, note);
		isMsgShown = true;
	}
}

/* ---------------------------------------------------------------------------------       */

EvaListView::EvaListView(QWidget *parent, const char *name, WFlags f)
	: QListView(parent, name, f), dId(-1), dGroup(-1)
{
	addColumn("1");
	setColumnWidthMode( 0, Manual);
	addColumn("2");
	setColumnWidthMode( 1, Manual);
	header()->hide();
	setSorting(0);
	setRootIsDecorated( false );
	setTreeStepSize( 20 );   
	setDragAutoScroll(true);
	setHScrollBarMode(QScrollView::AlwaysOff);
	
	setAcceptDrops( true );
	setSelectionMode( QListView::Extended );
	mToolTip = new EvaToolTip(this);
	isShowOnlineOnly = false;

	clearWFlags( WStaticContents );
	setWFlags( WNoAutoErase );

	static_cast<EvaListView*>(viewport())->clearWFlags( WStaticContents );
	static_cast<EvaListView*>(viewport())->setWFlags( WNoAutoErase );
}

EvaListView::~EvaListView()
{
	delete mToolTip;
	mToolTip = 0;
}

void EvaListView::setupPixmaps(QPixmap *gOpen, QPixmap *gClose, QPixmap *bNA, QPixmap *bMsg)
{
	EvaGroupItem::setPixmapOpen(gOpen);
	EvaGroupItem::setPixmapClose(gClose);
	EvaGroupItem::setPixmapMsg(bMsg);
	EvaBuddyItem::setPixmapNA(bNA);
	EvaBuddyItem::setPixmapMsg(bMsg);
	EvaQunItem::setPixmapMsg(bMsg);
}

void EvaListView::changeGroupTo(const int id, const int index)
{
	EvaGroupItem *gs = findGroupByID(id);
	EvaGroupItem *gd = findGroup(index);
	if(gs && gd){
		EvaBuddyItem *i = gs->takeBuddy(id);
		gd->addBuddy(i);
	}
}

bool EvaListView::addGroup(const QString &name, const int index)
{
	if(hasGroup(index)) return false;
	new EvaGroupItem(this, name, index);
	return true;
}

void EvaListView::deleteGroup(const int index)
{
	EvaGroupItem *group = findGroup(index);
	QListViewItem *item = group->firstChild();
	QListViewItem *next;
	while(item){
		next = item->nextSibling(); 
		delete item;
		item = next;
	}
	delete group;
}

bool EvaListView::addBuddy(const QString &nick, const int id, const QString signature, const int index, 
			QPixmap *on, QPixmap *off, EvaBuddyItem::Status status)
{
	EvaGroupItem *group = findGroup(index);
	if(!group) return false;
	if(hasBuddy(id)) {
		changeGroupTo(id, index);
		return false;
	}
	EvaBuddyItem *buddy = group->addBuddy(nick, id, signature, on, off, status);
	buddyMap[id] = buddy;
	return true;
}

void EvaListView::updateNick(const int id, const QString &nick)
{
	EvaBuddyItem *buddy = getBuddyRef(id);
	if(!buddy) return;
	buddy->updateNick(nick);
}

void EvaListView::updateSignature(const int id, const QString &sig)
{
	EvaBuddyItem *buddy = getBuddyRef(id);
	if(!buddy) return;
	buddy->updateSignature(sig);
}

void EvaListView::updateFacePixmaps(const int id, QPixmap *on, QPixmap *off)
{
	EvaBuddyItem *buddy = getBuddyRef(id);
	if(!buddy) return;
	buddy->updateFacePixmaps(on, off);
}

const std::list<std::string> EvaListView::getGroupNames()
{
	std::list<std::string> names;
	QTextCodec *codec = QTextCodec::codecForName("GB18030");
	EvaGroupItem *group = dynamic_cast<EvaGroupItem *>(firstChild());
	while(group){
		std::string n = (codec->fromUnicode(group->getGroupName())).data();
		names.push_back(n);
		group=dynamic_cast<EvaGroupItem *>(group->nextSibling());
	}
	return names;
}

const int EvaListView::getNumOfGroups() const
{
	return childCount();
}

const std::map<int, int> EvaListView::getGroupedBuddy()
{
	EvaGroupItem *group = dynamic_cast<EvaGroupItem *>(firstChild());
	EvaBuddyItem *item;
	std::map<int, int> l;
	int index;
	while(group){
		index = group->getGroupIndex();
		item = dynamic_cast<EvaBuddyItem *>(group->firstChild());
		while(item){
			l[item->getQQ()]=index;
			item = dynamic_cast<EvaBuddyItem *>(item->nextSibling());
		}
		group = dynamic_cast<EvaGroupItem *>(group->nextSibling());
	}
	return l;
}

const bool EvaListView::hasGroup(const int index) 
{
	if(findGroup(index)) return true;
	return false;
}

const bool EvaListView::hasBuddy(const int id)
{
	EvaBuddyItem *buddy = getBuddyRef(id);
	return (buddy != NULL);
}

EvaBuddyItem *EvaListView::getBuddyRef(const int id)
{
	std::map<const int, EvaBuddyItem *>::iterator iter;
	iter = buddyMap.find(id);
	if(iter == buddyMap.end()) return NULL;
	return iter->second;
}

void EvaListView::updateAllGroupTitles()
{
	EvaGroupItem *group = dynamic_cast<EvaGroupItem *>(firstChild());
	while(group){
		group->updateGroupTitle();
		group = dynamic_cast<EvaGroupItem *>(group->nextSibling());
	}
}

EvaGroupItem *EvaListView::updateGroupTitle(EvaBuddyItem *buddy, bool isGetGroupRefOnly)
{
	if(!buddy) return NULL;
	EvaGroupItem * g = dynamic_cast<EvaGroupItem *>(((QListViewItem*)(buddy))->parent());
	if(!g) return g;
	if(!isGetGroupRefOnly)
		g->updateGroupTitle();
	return g;
}

bool EvaListView::changeToOnline(const int id)
{
	EvaBuddyItem *buddy = getBuddyRef(id);
	if(!buddy) return false;
	buddy->slotChangeToOnline();
	if(!buddy->isVisible()) buddy->setVisible(true);
	updateGroupTitle(buddy);
	return true;
}

bool EvaListView::changeToLeave(const int id)
{
	EvaBuddyItem *buddy = getBuddyRef(id);
	if(!buddy) return false;
	buddy->slotChangeToLeave();
	if(!buddy->isVisible()) buddy->setVisible(true);
	updateGroupTitle(buddy);
	return true;
}

bool EvaListView::changeToOffline(const int id)
{
// 	EvaGroupItem * group = findGroupByID(id);
// 	if(!group) return false;
// 	return group->changeToOffline(id);
	EvaBuddyItem *buddy = getBuddyRef(id);
	if(!buddy) return false;
	buddy->slotChangeToOffline();
	if(isShowOnlineOnly && buddy->isVisible()) buddy->setVisible(false);
	updateGroupTitle(buddy);
	return true;
}

bool EvaListView::changeToInvisible(const int id)
{
// 	EvaGroupItem * group = findGroupByID(id);
// 	if(!group) return false;
// 	return group->changeToInvisible(id);
	EvaBuddyItem *buddy = getBuddyRef(id);
	if(!buddy) return false;
	buddy->slotChangeToInvisible();
	if(isShowOnlineOnly && buddy->isVisible()) buddy->setVisible(false);
	updateGroupTitle(buddy);
	return true;
}

bool EvaListView::startFlash(const int id)
{
	EvaBuddyItem *buddy = getBuddyRef(id);
	if(!buddy) return false;
	buddy->slotStartFlash();
	EvaGroupItem *g = updateGroupTitle(buddy, true);
	if(g)
		g->startFlash(id);
	return true;
}

bool EvaListView::stopFlash(const int id)
{
	EvaBuddyItem *buddy = getBuddyRef(id);
	if(!buddy) return false;
	buddy->slotStopFlash();
	EvaGroupItem *g = updateGroupTitle(buddy, true);
	if(g)
		g->stopFlash(id);
	return true;
}

bool EvaListView::startQunFlash(const int id)
{
	EvaGroupItem *group = findGroup(EvaUser::getQunIndex());
	if(!group) return false;
	return group->startFlash(id);
}

bool EvaListView::stopQunFlash(const int id)
{
	EvaGroupItem *group = findGroup(EvaUser::getQunIndex());
	if(!group) return false;
	return group->stopFlash(id);
}

EvaGroupItem *EvaListView::findGroup(const int index)
{
	EvaGroupItem *group = dynamic_cast<EvaGroupItem *>(firstChild());
	while(group){
		if(index==group->getGroupIndex()) return group;
		group = dynamic_cast<EvaGroupItem *>(group->nextSibling());
	}
	return NULL;
}

EvaGroupItem *EvaListView::findGroupByID(const int id)
{
	EvaGroupItem *g = updateGroupTitle(getBuddyRef(id));
	return g;
}

bool EvaListView::removeBuddy(const int id)
{
	EvaGroupItem * group = findGroupByID(id);
	if(!group) return false;
	buddyMap.erase(id);
	group->updateGroupTitle();
	return group->removeBuddy(id);
}

void EvaListView::showAll()
{
	EvaGroupItem *group = dynamic_cast<EvaGroupItem *>(firstChild());
	while(group){
		group->showAll();
		group = dynamic_cast<EvaGroupItem *>(group->nextSibling());
	}
	isShowOnlineOnly = false;
}

void EvaListView::showOnlineOnly()
{
	EvaGroupItem *group = dynamic_cast<EvaGroupItem *>(firstChild());
	while(group){
		group->showOnlineOnly();
		group = dynamic_cast<EvaGroupItem *>(group->nextSibling());
	}
	isShowOnlineOnly = true;
}

void EvaListView::refreshFace(const QSize &size)
{
	EvaBuddyItem::setFaceSize(size);
	EvaGroupItem *group = dynamic_cast<EvaGroupItem *>(firstChild());
	while(group){
		group->refreshFace();
		group = dynamic_cast<EvaGroupItem *>(group->nextSibling());
	}
}

void EvaListView::setFaceSize(const QSize &size)
{
	EvaBuddyItem::setFaceSize(size);
}

void EvaListView::addQun(QString &name, const int id, QPixmap *pic)
{
	EvaGroupItem *group = findGroup(EvaUser::getQunIndex());
	if(!group) return;
	if(group->hasQun(id)){
		group->updateQun(name, id, pic);
		return;
	}
	group->addQun(name, id, pic);
}

void EvaListView::updateQun(QString &name, const int id, QPixmap *pic)
{
	EvaGroupItem *group = findGroup(EvaUser::getQunIndex());
	if(!group) return;
	group->updateQun(name, id, pic);
}

void EvaListView::clear()
{
	QListView::clear();
	buddyMap.clear();
}

void EvaListView::keyPressEvent( QKeyEvent *e )
{
	EvaGroupItem *item = dynamic_cast<EvaGroupItem *>(currentItem());
	if ( (e->key() == Qt::Key_F2) && item ){
		item->setGroupName(item->getGroupName());  // this is to elimate the online number statistics
		item->setRenameEnabled(0, true);
		item->startRename(0);
	}else
		QListView::keyPressEvent(e);
}

void EvaListView::startDrag()
{
	EvaBuddyItem *item = dynamic_cast<EvaBuddyItem *>(currentItem());
	if(!item) return;
	EvaGroupItem * group = dynamic_cast<EvaGroupItem *>(currentItem()->parent());
	if(!group) return;
	dGroup = group->getGroupIndex();
	dId = item->getQQ();	
	closeAllGroups();
	QDragObject *d = new QTextDrag(QString::number(item->getQQ()), this);
	d->dragCopy();
}

void EvaListView::dragEnterEvent(QDragEnterEvent *event)
{
	if(dId == -1 || dGroup == -1) return;
	event->accept(QTextDrag::canDecode(event));
}

void EvaListView::dropEvent(QDropEvent *event)
{
	QPoint p(contentsToViewport(event->pos()));
	QListViewItem *i=itemAt( p );
	if(!i) return;
	EvaGroupItem * group = dynamic_cast<EvaGroupItem *>(i);
	if(!group){
		group = dynamic_cast<EvaGroupItem *>(i->parent());
		if(!group) return;
	}
	
	if(group->getGroupIndex() == EvaUser::getQunIndex())
		return;
	
	if(dGroup == group->getGroupIndex()) return; // if drop in same group
	if( EvaUser::getAnonymousIndex() == group->getGroupIndex()) return; // cannot drop buddy in Anonymous group
	
	
	QString text;
	if(QTextDrag::decode(event, text)){
		bool ok;
		int id = text.toInt(&ok);
		if(ok || id==dId ){
			if(EvaUser::getBlackIndex()  == group->getGroupIndex()) {
				emit deleteMeFrom(id);
				dId = -1;
				dGroup = -1;
				return;
			}
			// if drag buddy in Anonymous or Black List into other group
			if( dGroup == EvaUser::getAnonymousIndex() || dGroup == EvaUser::getBlackIndex()){ 
				emit requestAddBuddy(id);
				dId = -1;
				dGroup = -1;
				return;
			}
			EvaBuddyItem * buddy = findGroup(dGroup)->takeBuddy(dId);
			group->addBuddy(buddy);
			group->setOpen(true);
			emit groupChanged(id, group->getGroupIndex());
			dId = -1;
			dGroup = -1;
			updateAllGroupTitles();
			return;
		}
		
	}
}

void EvaListView::closeAllGroups()
{
	EvaGroupItem *group = dynamic_cast<EvaGroupItem *>(firstChild());
	while(group){
		group->setOpen(false);
		group = dynamic_cast<EvaGroupItem *>(group->nextSibling());
	}
}

void EvaListView::clearQunList( )
{
	EvaGroupItem *group = findGroup(EvaUser::getQunIndex());
	if(!group) return;
	group->clearQunGroup();
}

void EvaListView::removeQun( const int id )
{
	EvaGroupItem *group = findGroup(EvaUser::getQunIndex());
	if(!group) return;
	group->removeQun(id);
}

/* ---------------------------------------------------------------------------------       */

QPixmap *EvaQunItem::pixMsg =0;

EvaQunItem::EvaQunItem( QListViewItem * parent, const QString & name, const int qID, QPixmap * pic )
	: QListViewItem( parent, " "+name),
	isMsgShown(false), qunID(qID), qunName(name), qunPic(pic)
{
	//discuss = new EvaGroupItem(this, " " + i18n("Discuss Group"), EvaGroupItem::QunDiscuss);
	//groups = new EvaGroupItem(this, " " + i18n("Orgs in Qun"), EvaGroupItem::QunOrg);
	setQunPix(pic);
	timer = new QTimer();
	QObject::connect(timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
}

void EvaQunItem::setQunName(const QString &name)
{
	qunName = name;
	setText(0, " "+name);
}

void EvaQunItem::setQunPix(QPixmap *pix)
{
	qunPic = pix;
	if(qunPic)
		setPixmap(0, *qunPic);
}

const bool EvaQunItem::hasMessages() const
{
	if(timer->isActive())
		return true;
	return false;
}

QString EvaQunItem::tip()
{
	QTextCodec *codec = QTextCodec::codecForName("GB18030");
	
	QString decription = "";
	const Qun *qun = EvaMain::user->getQunList()->getQun(qunID);
	if(qun && qun->getDetails().getQunID() ){
		decription = codec->toUnicode(qun->getDetails().getDescription().c_str());
	}
	QString tip = "<table><tr><td align = left valign = middle><font color = blue><b>"+
			i18n("Qun") + ": </b></font>"+ qunName +"<br><b><font color = blue>"+ 
			i18n("Description") +": </font></b><br>  "+ decription + "</td></tr></table>";
	return tip;
}

void EvaQunItem::slotStartFlash( )
{
	if(!pixMsg) return; 
	setPixmap(1,*pixMsg);
	isMsgShown = true;
	if(!timer->isActive())
		timer->start(500, false);
	
}

void EvaQunItem::slotStopFlash( )
{
	if(timer->isActive())
		timer->stop();
	setPixmap(1,0);
	isMsgShown = false;
}

void EvaQunItem::slotTimeout( )
{
	if(!pixMsg) return ;
	if(isMsgShown){
		setPixmap(1,0);
		isMsgShown = false;
	}else{
		setPixmap(1,*pixMsg);
		isMsgShown = true;
	}
}




