/*
 * infodlg.cpp - handle vcard
 * Copyright (C) 2001, 2002  Justin Karneges
 *
 * 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include"infodlg.h"

#include<qlayout.h>
#include<qlabel.h>
#include<qtabwidget.h>
#include<qpushbutton.h>
#include<qlineedit.h>
#include<qmessagebox.h>
#include<qtextedit.h>
#include<qfiledialog.h> 
#include<qbuffer.h>
#include"xmpp.h"
#include"msgmle.h"
#include"userlist.h"
#include"xmpp_vcard.h"
#include"xmpp_tasks.h"
#include"psiaccount.h"
#include"busywidget.h"
#include"common.h"
#include"vcardfactory.h"
#include"iconwidget.h"


using namespace XMPP;
		
class InfoDlg::Private
{
public:
	Private() {}

	int type;
	Jid jid;
	VCard vcard;
	PsiAccount *pa;
	BusyWidget *busy;
	bool te_edited;
	int actionType;
	JT_VCard *jt;
	bool cacheVCard;
	PsiTextView* te_status;
	QByteArray photo;
};

InfoDlg::InfoDlg(int type, const Jid &j, const VCard &vcard, PsiAccount *pa, QWidget *parent, const char *name, bool cacheVCard)
:InfoUI(parent, name, false, WDestructiveClose)
{
	d = new Private;
	d->type = type;
	d->jid = j;
	d->vcard = vcard;
	d->pa = pa;
	d->te_edited = false;
	d->jt = 0;
	d->pa->dialogRegister(this, j);
	d->cacheVCard = cacheVCard;
	d->te_status = NULL;
	d->busy = busy;

	te_desc->setTextFormat(QTextEdit::PlainText);

	setCaption(d->jid.full());
#ifndef Q_WS_MAC
	setIcon(IconsetFactory::icon("psi/vCard"));
#endif

	connect(pb_refresh, SIGNAL(clicked()), this, SLOT(doRefresh()));
	connect(pb_refresh, SIGNAL(clicked()), this, SLOT(updateStatus()));
	connect(te_desc, SIGNAL(textChanged()), this, SLOT(textChanged()));
	connect(pb_open, SIGNAL(clicked()), this, SLOT(selectPhoto()));
	connect(pb_clear, SIGNAL(clicked()), this, SLOT(clearPhoto()));

	if(d->type == Self) {
		connect(pb_submit, SIGNAL(clicked()), this, SLOT(doSubmit()));
	}
	else {
		// Add a status tab
		d->te_status = new PsiTextView(tabwidget);
		d->te_status->setReadOnly(true);
		d->te_status->setTextFormat(RichText);
		tabwidget->addTab(d->te_status, tr("Status"));
		updateStatus();

		// Hide buttons
		pb_submit->hide();
		pb_open->hide();
		pb_clear->hide();
		ly_photo->setSpacing(0);
		setReadOnly(true);
	}

	setData(d->vcard);
}

InfoDlg::~InfoDlg()
{
	d->pa->dialogUnregister(this);
	delete d;
}

/*void InfoDlg::closeEvent(QCloseEvent *e)
{
	e->accept();
	reject();
}*/

void InfoDlg::done(int r)
{
	// don't close if submitting
	if(d->busy->isActive() && d->actionType == 1)
		return;

	if(d->type == Self && edited()) {
		int n = QMessageBox::information(this, tr("Warning"), tr("You have not published your account information changes.\nAre you sure you want to discard them?"), tr("Close and discard"), tr("Don't close"));
		if(n != 0)
			return;
	}

	// cancel active transaction (refresh only)
	if(d->busy->isActive() && d->actionType == 0) {
		delete d->jt;
		d->jt = 0;
	}

	QDialog::done(r);
}

void InfoDlg::jt_finished()
{
	d->busy->stop();
	pb_refresh->setEnabled(true);
	pb_submit->setEnabled(true);
	pb_close->setEnabled(true);
	fieldsEnable(true);

	if(d->jt->success()) {
		if(d->actionType == 0) {
			d->vcard = d->jt->vcard();
			setData(d->vcard);
		}
		else if(d->actionType == 1) {
			d->vcard = d->jt->vcard();
			if ( d->cacheVCard )
				VCardFactory::setVCard(d->jid, d->vcard);
			setData(d->vcard);
		}

		if(d->jid.compare(d->pa->jid(), false)) {
			if (!d->vcard.nickName().isEmpty())
				d->pa->setNick(d->vcard.nickName());
			else
				d->pa->setNick(d->pa->jid().user());
		}

		if(d->actionType == 1)
			QMessageBox::information(this, tr("Success"), tr("Your account information has been published."));
	}
	else {
		if(d->actionType == 0) {
			if(d->type == Self)
				QMessageBox::critical(this, tr("Error"), tr("Unable to retrieve your account information.  Perhaps you haven't entered any yet."));
			else
				QMessageBox::critical(this, tr("Error"), tr("Unable to retrieve information about this contact.\nReason: %1").arg(d->jt->statusString()));
		}
		else {
			QMessageBox::critical(this, tr("Error"), tr("Unable to publish your account information.\nReason: %1").arg(d->jt->statusString()));
		}
	}

	d->jt = 0;
}

void InfoDlg::setData(const VCard &i)
{
	le_fullname->setText( i.fullName() );
	le_nickname->setText( i.nickName() );
	le_bday->setText( i.bdayStr() );

	QString email;
	if ( !i.emailList().isEmpty() )
		email = i.emailList()[0].userid;
	le_email->setText( email );

	le_homepage->setText( i.url() );

	QString phone;
	if ( !i.phoneList().isEmpty() )
		phone = i.phoneList()[0].number;
	le_phone->setText( phone );

	VCard::Address addr;
	if ( !i.addressList().isEmpty() )
		addr = i.addressList()[0];
	le_street->setText( addr.street );
	le_ext->setText( addr.extaddr );
	le_city->setText( addr.locality );
	le_state->setText( addr.region );
	le_pcode->setText( addr.pcode );
	le_country->setText( addr.country );

	le_orgName->setText( i.org().name );

	QString unit;
	if ( !i.org().unit.isEmpty() )
		unit = i.org().unit[0];
	le_orgUnit->setText( unit );

	le_title->setText( i.title() );
	le_role->setText( i.role() );
	te_desc->setText( i.desc() );
	
	if ( !i.photo().isEmpty() ) {
		//printf("There is a picture...\n");
		d->photo = i.photo();
		updatePhoto();
	}
	else
		clearPhoto();

	setEdited(false);
}

void InfoDlg::updatePhoto() 
{
	int max_width = label_photo->width() - 20; // FIXME: Ugly magic number
	int max_height = label_photo->height() - 20; // FIXME: Ugly magic number
	
	QImage img(d->photo);
	QImage img_scaled;
	if (img.width() > max_width || img.height() > max_height) {
		img_scaled = img.smoothScale(max_width, max_height,QImage::ScaleMin);
	}
	else {
		img_scaled = img;
	}
	label_photo->setPixmap(QPixmap(img_scaled));
}

void InfoDlg::fieldsEnable(bool x)
{
	le_fullname->setEnabled(x);
	le_nickname->setEnabled(x);
	le_bday->setEnabled(x);
	le_email->setEnabled(x);
	le_homepage->setEnabled(x);
	le_phone->setEnabled(x);
	pb_open->setEnabled(x);
	pb_clear->setEnabled(x);

	le_street->setEnabled(x);
	le_ext->setEnabled(x);
	le_city->setEnabled(x);
	le_state->setEnabled(x);
	le_pcode->setEnabled(x);
	le_country->setEnabled(x);

	le_orgName->setEnabled(x);
	le_orgUnit->setEnabled(x);
	le_title->setEnabled(x);
	le_role->setEnabled(x);
	te_desc->setEnabled(x);

	setEdited(false);
}

void InfoDlg::setEdited(bool x)
{
	le_fullname->setEdited(x);
	le_nickname->setEdited(x);
	le_bday->setEdited(x);
	le_email->setEdited(x);
	le_homepage->setEdited(x);
	le_phone->setEdited(x);
	le_street->setEdited(x);
	le_ext->setEdited(x);
	le_city->setEdited(x);
	le_state->setEdited(x);
	le_pcode->setEdited(x);
	le_country->setEdited(x);
	le_orgName->setEdited(x);
	le_orgUnit->setEdited(x);
	le_title->setEdited(x);
	le_role->setEdited(x);

	d->te_edited = x;
}

bool InfoDlg::edited()
{
	bool x = false;

	if(le_fullname->edited()) x = true;
	if(le_nickname->edited()) x = true;
	if(le_bday->edited()) x = true;
	if(le_email->edited()) x = true;
	if(le_homepage->edited()) x = true;
	if(le_phone->edited()) x = true;
	if(le_street->edited()) x = true;
	if(le_ext->edited()) x = true;
	if(le_city->edited()) x = true;
	if(le_state->edited()) x = true;
	if(le_pcode->edited()) x = true;
	if(le_country->edited()) x = true;
	if(le_orgName->edited()) x = true;
	if(le_orgUnit->edited()) x = true;
	if(le_title->edited()) x = true;
	if(le_role->edited()) x = true;
	if(d->te_edited) x = true;

	return x;
}

void InfoDlg::setReadOnly(bool x)
{
	le_fullname->setReadOnly(x);
	le_nickname->setReadOnly(x);
	le_bday->setReadOnly(x);
	le_email->setReadOnly(x);
	le_homepage->setReadOnly(x);
	le_phone->setReadOnly(x);
	le_street->setReadOnly(x);
	le_ext->setReadOnly(x);
	le_city->setReadOnly(x);
	le_state->setReadOnly(x);
	le_pcode->setReadOnly(x);
	le_country->setReadOnly(x);
	le_orgName->setReadOnly(x);
	le_orgUnit->setReadOnly(x);
	le_title->setReadOnly(x);
	le_role->setReadOnly(x);
	te_desc->setReadOnly(x);
}

void InfoDlg::doRefresh()
{
	if(!d->pa->checkConnected(this))
		return;
	if(!pb_refresh->isEnabled())
		return;
	if(d->busy->isActive())
		return;

	pb_submit->setEnabled(false);
	pb_refresh->setEnabled(false);
	fieldsEnable(false);

	d->actionType = 0;
	d->busy->start();

	d->jt = VCardFactory::getVCard(d->jid, d->pa->client()->rootTask(), this, SLOT(jt_finished()), d->cacheVCard);
}

void InfoDlg::doSubmit()
{
	if(!d->pa->checkConnected(this))
		return;
	if(!pb_submit->isEnabled())
		return;
	if(d->busy->isActive())
		return;

	VCard submit_vcard = makeVCard();

	pb_submit->setEnabled(false);
	pb_refresh->setEnabled(false);
	pb_close->setEnabled(false);
	fieldsEnable(false);

	d->actionType = 1;
	d->busy->start();

	d->jt = new JT_VCard(d->pa->client()->rootTask());
	connect(d->jt, SIGNAL(finished()), SLOT(jt_finished()));
	d->jt->set(submit_vcard);
	d->jt->go(true);
}

VCard InfoDlg::makeVCard()
{
	VCard v;

	v.setFullName( le_fullname->text() );
	v.setNickName( le_nickname->text() );
	v.setBdayStr( le_bday->text() );

	if ( !le_email->text().isEmpty() ) {
		VCard::Email email;
		email.internet = true;
		email.userid = le_email->text();

		VCard::EmailList list;
		list << email;
		v.setEmailList( list );
	}

	v.setUrl( le_homepage->text() );

	if ( !le_phone->text().isEmpty() ) {
		VCard::Phone p;
		p.home = true;
		p.voice = true;
		p.number = le_phone->text();

		VCard::PhoneList list;
		list << p;
		v.setPhoneList( list );
	}
	
	if ( !d->photo.isEmpty() ) {
		//printf("Adding a pixmap to the vCard...\n");
		v.setPhoto( d->photo );
	}

	if ( !le_street->text().isEmpty() ||
	     !le_ext->text().isEmpty()    ||
	     !le_city->text().isEmpty()   ||
	     !le_state->text().isEmpty()  ||
	     !le_pcode->text().isEmpty()  ||
	     !le_country->text().isEmpty() )
	{
		VCard::Address addr;
		addr.home = true;
		addr.street = le_street->text();
		addr.extaddr = le_ext->text();
		addr.locality = le_city->text();
		addr.region = le_state->text();
		addr.pcode = le_pcode->text();
		addr.country = le_country->text();

		VCard::AddressList list;
		list << addr;
		v.setAddressList( list );
	}

	VCard::Org org;

	org.name = le_orgName->text();

	if ( !le_orgUnit->text().isEmpty() )
		org.unit << le_orgUnit->text();

	v.setOrg( org );

	v.setTitle( le_title->text() );
	v.setRole( le_role->text() );
	v.setDesc( te_desc->text() );

	return v;
}

void InfoDlg::textChanged()
{
	d->te_edited = true;
}

/*!
 * Opens a file browser dialog, and if selected, calls the setPreviewPhoto with the consecuent path.
 * \see setPreviewPhoto(const QString& path)
*/
void InfoDlg::selectPhoto()
{
	while(1) {
		if(option.lastPath.isEmpty())
			option.lastPath = QDir::homeDirPath();
		QString str = QFileDialog::getOpenFileName(option.lastPath, tr("Images (*.png *.xpm *.jpg *.PNG *.XPM *.JPG)"), this, 0, tr("Choose a file"));
		if(!str.isEmpty()) {
			QFileInfo fi(str);
			if(!fi.exists()) {
				QMessageBox::information(this, tr("Error"), tr("The file specified does not exist."));
				continue;
			}
			option.lastPath = fi.dirPath();
			//printf(QDir::convertSeparators(fi.filePath()));
			
			// put the image in the preview box
			setPreviewPhoto(str);
		}
		break;
	}
	
}

/*!
 * Loads the image from the requested URL, and inserts the resized image into the preview box.
 * \param path image file to load
*/
void InfoDlg::setPreviewPhoto(const QString& path)
{
	QFile photo_file(path);
	if (!photo_file.open(IO_ReadOnly))
		return;
	
	QByteArray photo_data = photo_file.readAll();
	QImage photo_image(photo_data);
	if(!photo_image.isNull()) {
		d->photo = photo_data;
		updatePhoto();
		d->te_edited = true;
	}
}

/*!
 * Clears the preview image box and marks the te_edited signal in the private.
*/
void InfoDlg::clearPhoto()
{
	// this will cause the pixmap disappear
	label_photo->setText(tr("Picture not\navailable"));
	d->photo = QByteArray();
	
	// the picture changed, so notify there are some changes done
	d->te_edited = true;
}

/*!
 * Updates the status info of the contact
 */
void InfoDlg::updateStatus()
{
	if (!d->te_status)
		return;

	UserListItem *u = d->pa->find(d->jid);
	if(u) {
		d->te_status->setText(u->makeDesc());
	}
	else {
		d->te_status->clear();
	}
}
