/***************************************************************************
                        dcuserslist.cpp  -  description
                             -------------------
    begin                : Thu Nov 21 2002
    copyright            : (C) 2002 by François Gannaz
 ***************************************************************************/

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

#include "dcuserslist.h"

#include <stdlib.h>

#include <qcursor.h>
#include <QEvent>
#include <QResizeEvent>
#include <QShowEvent>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QFile>
#include <QList>
#include <QHeaderView>

#include "dcconfig.h"
#include "dcevent.h"
#include "dcconnectionmanager.h"
#include "dcmenuhandler.h"
#include "dciconloader.h"
#include "dctransferview.h"
#include "dcguiutils.h"

#include <dclib/core/cstring.h>
#include <dclib/core/cbytearray.h>

DCUsersList * g_pUsersList = 0;

/** */
DCUsersList::DCUsersList( QWidget * parent ) : QWidget( parent )
{
	setupUi(this);
	
	setWindowIcon( g_pIconLoader->GetPixmap(eiUSERS) );
	
	lastFriendsWidth = -1;
	
	/*
	 * disable this, we are adjusting the column widths because
	 * QTreeView only resizes the last column
	 */
	TreeWidget_FRIENDS->header()->setStretchLastSection(false);
	
	/* I have no idea why QT4 defaults to descending order */
	TreeWidget_FRIENDS->sortByColumn( 0, Qt::AscendingOrder );
	
	if ( (parent != 0) && (qobject_cast<QMdiArea*>(parent) != 0) )
	{
		m_pContainerWindow = new QMdiSubWindow();
		m_pContainerWindow->setWidget(this);
	}
	else
	{
		m_pContainerWindow = 0;
	}

	InitDocument();

	g_pUsersList = this;
}

/** */
DCUsersList::~DCUsersList()
{
	g_pUsersList = NULL;

	for ( FriendMap::const_iterator it = m_FriendMap.constBegin(); it != m_FriendMap.constEnd(); ++it )
	{
		delete it.value();
	}

	m_FriendMap.clear();
	
	if ( m_pContainerWindow )
	{
		m_pContainerWindow->setWidget(0); // otherwise the QMdiSubWindow will delete this again
		delete m_pContainerWindow;
		m_pContainerWindow = 0;
	}
}

/** */
void DCUsersList::showEvent( QShowEvent * event )
{
	QWidget::showEvent( event );
	
	if ( isVisible() )
	{
		SizeColumnsPreservingRatios();
	}
}

/** */
void DCUsersList::resizeEvent( QResizeEvent * )
{
	SizeColumnsPreservingRatios();
}

/** */
void DCUsersList::closeEvent( QCloseEvent * e )
{
	QWidget::closeEvent( e );
	
	if ( m_pContainerWindow && m_pContainerWindow->parent() )
	{
		/* Using QMdiArea::removeSubWindow() breaks tabs mode but this works */
		m_pContainerWindow->setParent(0);
	}
}

/** */
void DCUsersList::SizeColumnsPreservingRatios()
{
	if ( TreeWidget_FRIENDS->isVisible() )
	{
		int width = TreeWidget_FRIENDS->width();
		if ( width > 0 )
		{
			if ( lastFriendsWidth == -1 )
			{
				TreeWidget_FRIENDS->setColumnWidth( 0, width/4 );
				TreeWidget_FRIENDS->setColumnWidth( 1, width/4 );
				TreeWidget_FRIENDS->setColumnWidth( 2, width/4 );
				TreeWidget_FRIENDS->setColumnWidth( 3, width/4 );
				
				lastFriendsWidth = TreeWidget_FRIENDS->width();
			}
			else if ( lastFriendsWidth != width )
			{
				DCGuiUtils::AdjustColumnWidths( TreeWidget_FRIENDS, lastFriendsWidth );
				lastFriendsWidth = TreeWidget_FRIENDS->width();
			}
		}
	}
}

/** */
void DCUsersList::InitDocument()
{
	StringMap * map;

	// restore settings
	if ( g_pConfig->GetMap("USERVIEW",map) )
	{
		if ( ((*map)["WIDTH"].toInt() > 0) && ((*map)["HEIGHT"].toInt() > 0) )
		{
			if ( m_pContainerWindow != 0 )
			{
				m_pContainerWindow->setGeometry( (*map)["X"].toInt(), (*map)["Y"].toInt(), (*map)["WIDTH"].toInt(), (*map)["HEIGHT"].toInt() );
			}
		}
	}
	
	connect( TreeWidget_FRIENDS, SIGNAL(customContextMenuRequested( const QPoint & )), this, SLOT(slotRightButtonClickedFriendList( const QPoint & )) );

	// load friends list
	g_pConfig->LoadDCFriendList( &m_FriendMap );

	ShowFriendsList();
}

/** */
void DCUsersList::DeInitDocument()
{
	if ( m_pContainerWindow == 0 )
	{
		return;
	}
	
	StringMap * map;

	// save search view settings
	g_pConfig->GetMap("USERVIEW",map);

	(*map)["X"]         = QString().setNum(m_pContainerWindow->x());
	(*map)["Y"]         = QString().setNum(m_pContainerWindow->y());
	(*map)["WIDTH"]     = QString().setNum(m_pContainerWindow->width());
	(*map)["HEIGHT"]    = QString().setNum(m_pContainerWindow->height());
	(*map)["VISIBLE"]   = QString().setNum(m_pContainerWindow->isVisible());
	(*map)["MAXIMIZED"] = QString().setNum(m_pContainerWindow->isMaximized());
	(*map)["MINIMIZED"] = QString().setNum(m_pContainerWindow->isMinimized());
}

/** friend event handling */
void DCUsersList::customEvent( QEvent * event )
{
	if ( event->type() == EVENT_UPDATE_FRIEND )
	{
		DCFriendObject * FriendObject;
		eUserAwayMode awaymode;
		DC_FriendEvent * e = (DC_FriendEvent*)event;

		if ( (e->m_pFriendObject->m_sName.isEmpty()) && (g_pConnectionManager) )
		{
			// check all friends online state
			for ( FriendMap::const_iterator it = m_FriendMap.constBegin(); it != m_FriendMap.constEnd(); ++it )
			{
				FriendObject = it.value();
				CString empty;
				if ( g_pConnectionManager->IsUserOnline( FriendObject->m_sName.toAscii().constData(), empty, empty, 0 ) )
				{
					awaymode = euamONLINE;
				}
				else
				{
					awaymode = euamOFFLINE;
				}

				SetAwayMode( FriendObject, awaymode );
			}
		}
		else
		{
			FriendObject = m_FriendMap.value(e->m_pFriendObject->m_sName);
			if ( FriendObject != 0 )
			{
				SetAwayMode( FriendObject, e->m_pFriendObject->m_eAwayMode );
			}
		}
		
		event->accept();
	}
	else
	{
		event->ignore();
	}
}

/** */
void DCUsersList::ShowFriendsList()
{
	QImage im;
	DCFriendObject * FriendObject;

	for ( FriendMap::const_iterator it = m_FriendMap.constBegin(); it != m_FriendMap.constEnd(); ++it )
	{
		FriendObject = it.value();
		
		FriendObject->m_pItem = new QTreeWidgetItem( TreeWidget_FRIENDS  );
		FriendObject->m_pItem->setText( 0, FriendObject->m_sName );

		FriendObject->m_pItem->setIcon(0,QIcon(g_pIconLoader->GetPixmap(eiBALL_RED)));

		if ( !(FriendObject->m_sImageFileName.isEmpty()) )
		{
			if ( im.load(FriendObject->m_sImageFileName) )
			{
				im = im.scaled(32,32,Qt::KeepAspectRatio,Qt::SmoothTransformation);
				FriendObject->m_pItem->setIcon(1,QIcon(QPixmap::fromImage(im)));
			}
		}
		
		if ( FriendObject->m_bPermSlot )
		{
			FriendObject->m_pItem->setText(2, tr("Permanent slot"));
		}
		else
		{
			FriendObject->m_pItem->setText(2, QString());
		}
		
		if ( FriendObject->m_bIgnore )
		{
			FriendObject->m_pItem->setText(3, tr("Ignore"));
		}
		else
		{
			FriendObject->m_pItem->setText(3, QString());
		}
	}
}

/** */
void DCUsersList::DelFriend( QString name )
{
	DCFriendObject * FriendObject = m_FriendMap.value(name);

	if ( FriendObject != 0 )
	{
		// remove slot if necessary
		if ( FriendObject->m_bPermSlot )
		{
			g_pTransferView->DLM_AddUserSlot(FriendObject->m_sName.toAscii().constData(), FriendObject->m_sHubName.toAscii().constData(), 0);
		}

		delete FriendObject->m_pItem;

		// remove from list
		m_FriendMap.remove(name);
		delete FriendObject;

		// save list
		g_pConfig->SaveDCFriendList( &m_FriendMap );
	}
}

/** */
void DCUsersList::AddFriend( QString name, QString hubname, QString hubhost, QString description )
{
	DCFriendObject * FriendObject = m_FriendMap.value(name);
	
	if ( FriendObject == 0 )
	{
		FriendObject = new DCFriendObject();

		FriendObject->m_sName        = name;
		FriendObject->m_sHubName     = hubname;
		FriendObject->m_sHubHost     = hubhost;
		FriendObject->m_sDescription = description;

		FriendObject->m_pItem = new QTreeWidgetItem( TreeWidget_FRIENDS );
		FriendObject->m_pItem->setText( 0, FriendObject->m_sName );

		m_FriendMap.insert(name,FriendObject);

		eUserAwayMode awaymode = euamNONE;
		if ( g_pConnectionManager )
		{
			CString empty;
			if ( g_pConnectionManager->IsUserOnline( FriendObject->m_sName.toAscii().constData(), empty, empty, 0 ) )
			{
				awaymode = euamONLINE;
			}
		}

		SetAwayMode( FriendObject, awaymode );

		// add permanent slot if granted
		if (FriendObject->m_bPermSlot)
		{
			g_pTransferView->DLM_AddUserSlot( name.toAscii().constData(), hubname.toAscii().constData(), 0, true );
		}
		
		// save friendlist
		g_pConfig->SaveDCFriendList( &m_FriendMap );
	}
}

/** */
void DCUsersList::UpdateFriend( QString /*name*/, QString /*host*/, QString /*description*/ )
{
}

/** */
bool DCUsersList::AddFriendPhoto( QString name, CByteArray * data )
{
	bool res = false;
	QFile f;
	QString s;
	int i;

	DCFriendObject * FriendObject = m_FriendMap.value(name);
	if ( FriendObject != 0 )
	{
		s = FriendObject->m_sImageFileName;

		if ( !s.isEmpty() )
		{
			f.setFileName(s);
			if ( f.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
			{
				f.write((const char*)data->Data(),data->Size());
				f.close();
			}
			else
			{
				s = QString();
			}
		}

		if ( s.isEmpty() )
		{
			// create new image
			for(i=0;i<200;i++)
			{
				s = QString::fromAscii(g_pConfig->GetImagePath().Data()) + QString().setNum(i) + ".png";
				if ( f.exists(s) == false )
				{
					break;
				}
			}

			if ( i < 200 )
			{
				f.setFileName(s);
				if ( f.open( QIODevice::WriteOnly ) )
				{
					f.write((const char*)data->Data(),data->Size());
					f.close();

					FriendObject->m_sImageFileName = s;
				}
				else
				{
					printf("AddFriendPhoto: can't open file '%s'\n",s.toAscii().constData());
				}
			}
		}

		// save friendlist
		g_pConfig->SaveDCFriendList( &m_FriendMap );

		QImage im;

		if ( !(FriendObject->m_sImageFileName.isEmpty()) )
		{
			if ( im.load(FriendObject->m_sImageFileName) )
			{
				im = im.scaled(32,32,Qt::KeepAspectRatio,Qt::SmoothTransformation);
				FriendObject->m_pItem->setIcon(1,QIcon(QPixmap::fromImage(im)));
			}
		}
	}

	return res;
}

/** */
void DCUsersList::SetAwayMode( DCFriendObject * obj, eUserAwayMode e )
{
	if ( !obj || !obj->m_pItem )
	{
		return;
	}

	if ( obj->m_eAwayMode != e )
	{
		obj->m_eAwayMode = e;

		switch(obj->m_eAwayMode)
		{
			case euamNORMAL:
			case euamONLINE:
				obj->m_pItem->setIcon(0,QIcon(g_pIconLoader->GetPixmap(eiBALL_GREEN)));
				// add a permanent slot for friend if granted
				if (obj->m_bPermSlot)
				{
					g_pTransferView->DLM_AddUserSlot(obj->m_sName.toAscii().constData(), obj->m_sHubName.toAscii().constData(), 0, true );
				}
				break;
			case euamAWAY:
				obj->m_pItem->setIcon(0,QIcon(g_pIconLoader->GetPixmap(eiBALL_YELLOW)));
				// add a permanent slot for friend if granted
				if (obj->m_bPermSlot)
				{
					g_pTransferView->DLM_AddUserSlot(obj->m_sName.toAscii().constData(), obj->m_sHubName.toAscii().constData(), 0, true );
				}
				break;
			// case euamNONE:
			// case euamOFFLINE:
			default:
				obj->m_pItem->setIcon(0,QIcon(g_pIconLoader->GetPixmap(eiBALL_RED)));
				// remove the permanent slot for the friend if one is granted
				if (obj->m_bPermSlot)
				{
					g_pTransferView->DLM_AddUserSlot(obj->m_sName.toAscii().constData(), obj->m_sHubName.toAscii().constData(), 0);
				}
				break;
		}
	}
}

/** */
void DCUsersList::slotRightButtonClickedFriendList( const QPoint & )
{
	QAction * chosen = 0;
	QMenu *m;
	QList<QTreeWidgetItem*> selitems = TreeWidget_FRIENDS->selectedItems();
	QTreeWidgetItem * curitem;
	DCFriendObject * FriendObject;

	if ( selitems.size() == 0 )
	{
		return;
	}

	m = new QMenu(this);

	QAction * remove = DCMenuHandler::addAction( m, emiREMOVE );
	QAction * addSlot = m->addAction( QIcon( g_pIconLoader->GetPixmap(eiEDITADD) ), tr("Grant permanent slot") );
	QAction * removeSlot = m->addAction( QIcon( g_pIconLoader->GetPixmap(eiEDITDELETE) ), tr("Remove permanent slot") );
	QAction * ignore = m->addAction(tr("Ignore chat messages"));
	QAction * unignore = m->addAction(tr("Show chat messages"));
	
	chosen = m->exec(QCursor::pos());

	delete m;

	if ( chosen == 0 )
	{
		return;
	}

	if ( chosen == remove )
	{
	        for ( int i = 0; i < selitems.size(); i++ )
	        {
			curitem = selitems.at(i);
			DelFriend(curitem->text(0));
		}
	}
	else if ( chosen == addSlot )
	{
		for ( int i = 0; i < selitems.size(); i++ )
		{
			curitem = selitems.at(i);
			
			if ( curitem->text(2).isEmpty() )
			{
				curitem->setText(2, tr("Permanent slot"));
				FriendObject = m_FriendMap.value(curitem->text(0));
				if ( FriendObject != 0 )
				{
					//printf("Adding permanment slot for %s\n", FriendObject->m_sName.toAscii().constData());
					FriendObject->m_bPermSlot = true;
					CString empty;
					if (g_pConnectionManager->IsUserOnline( FriendObject->m_sName.toAscii().constData(), empty, empty, 0 ))
					{
						g_pTransferView->DLM_AddUserSlot(FriendObject->m_sName.toAscii().constData(), FriendObject->m_sHubName.toAscii().constData(), 0, true );
					}
				}
			}
		}
		
		g_pConfig->SaveDCFriendList( &m_FriendMap );
	}
	else if ( chosen == removeSlot )
	{
		for ( int i = 0; i < selitems.size(); i++ )
		{	
			curitem = selitems.at(i);
			
			if (curitem->text(2) == tr("Permanent slot"))
			{
				curitem->setText(2, QString());
				FriendObject = m_FriendMap.value(curitem->text(0));
				if ( FriendObject != 0 )
				{
					//printf("Removing permanment slot for %s\n", FriendObject->m_sName.toAscii().constData());
					FriendObject->m_bPermSlot = false;
					CString empty;
					if (g_pConnectionManager->IsUserOnline( FriendObject->m_sName.toAscii().constData(), empty, empty, 0 ))
					{
						g_pTransferView->DLM_AddUserSlot(FriendObject->m_sName.toAscii().constData(), FriendObject->m_sHubName.toAscii().constData(), 0);
					}
				}
			}
		}
		
		g_pConfig->SaveDCFriendList( &m_FriendMap );
	}
	else if ( chosen == ignore )
	{
		for ( int i = 0; i < selitems.size(); i++ )
		{
			curitem = selitems.at(i);
			
			curitem->setText(3, tr("Ignore"));
			
			FriendObject = m_FriendMap.value(curitem->text(0));
			if ( FriendObject != 0 )
			{
				FriendObject->m_bIgnore = true;
			}
		}
		
		g_pConfig->SaveDCFriendList( &m_FriendMap );
	}
	else if ( chosen == unignore )
	{
		for ( int i = 0; i < selitems.size(); i++ )
		{
			curitem = selitems.at(i);
			
			curitem->setText(3, QString());
			
			FriendObject = m_FriendMap.value(curitem->text(0));
			if ( FriendObject != 0 )
			{
				FriendObject->m_bIgnore = false;
			}
		}
		
		g_pConfig->SaveDCFriendList( &m_FriendMap );
	}
}

/** Returns true if the nick is in the friend list */
bool DCUsersList::isNickInList( QString name )
{
	return m_FriendMap.contains(name);
}

/** Returns true if the nick is on ignore */
bool DCUsersList::ignoreNick( QString nick )
{
	DCFriendObject * FriendObject = m_FriendMap.value(nick);

	if ( FriendObject != 0 )
	{
		return FriendObject->m_bIgnore;
	}
	else
	{
		return false;
	}	
}

/** Sets the ignore status of a nick*/
void DCUsersList::setIgnore( QString nick, bool ignore )
{
	DCFriendObject * FriendObject = m_FriendMap.value(nick);

	if ( FriendObject != 0 )
	{
		FriendObject->m_bIgnore = ignore;
		if ( ignore )
		{
			FriendObject->m_pItem->setText(3, tr("Ignore"));
		}
		else
		{
			FriendObject->m_pItem->setText(3, QString());
		}
		g_pConfig->SaveDCFriendList( &m_FriendMap );
	}
}
