#include <addresseeselector.h>
#include <qstringlist.h>
#include <qlayout.h>
#include <klocale.h>
#include <klistview.h>
#include <klistviewsearchline.h>
#include <kabc/addressbook.h>
#include <kabc/stdaddressbook.h>
#include <kabc/phonenumber.h>
#include <kabc/picture.h>
#include <kio/netaccess.h>
#include <kmessagebox.h>
#include <kapplication.h>
#include <qpixmap.h>
#include <qimage.h>
#include <qheader.h>
#include <kpopupmenu.h>

static const int IMAGE_HEIGHT = 64;
static const int IMAGE_WIDTH  = 45;

/**
 * Addressee View: a specialized KListView that features Addressee columns
 */
AddresseeView::AddresseeView( QWidget *parent,
			      const char *name ) :
  KListView( parent, name )
{
  int i;
  for ( i=0; i < ColumnsNumber; i++ )
    addColumn( "" );

  setColumnText( Picture, i18n( "Picture" ) );
  setColumnText( Name, i18n( "Name" ) );
  setColumnText( WorkInfo, i18n( "Work Information" ) );
  setColumnText( PreferredEmail,i18n( "Preferred Email" ) );
  setColumnText( Emails, i18n( "Emails" ) );
  setColumnText( PreferredPhone, i18n( "Preferred Phone" ) );
  setColumnText( Phones, i18n( "Phones" ) );
  setColumnText( MobilePhone, i18n( "Mobile Phone" ) );
  setColumnText( HomePhone, i18n( "Home Phone" ) );
  setColumnText( HomeFax, i18n( "Home Fax" ) );
  setColumnText( WorkPhone, i18n( "Work Phone" ) );
  setColumnText( WorkFax, i18n( "Work Fax" ) );
  setColumnText( PreferredAddress, i18n( "Preferred Address" ) );
  setColumnText( Addresses, i18n( "Addresses" ) );
  setColumnText( HomeAddress, i18n( "Home Address" ) );
  setColumnText( WorkAddress, i18n( "Work Address" ) );
  setColumnText( Categories, i18n( "Categories" ) );

  setShowSortIndicator( true );
  setAllColumnsShowFocus( true );
  setResizeMode( LastColumn );

  restoreLayout( KGlobal::config(), "AddresseeSelectorColumnsLayout" );

  for ( int i=0; i < columns(); i++ )
    if ( columnWidth( i ) <= 0 )
      hideColumn( i );
}

AddresseeView::~AddresseeView( void )
{
  saveLayout( KGlobal::config(), "AddresseeSelectorColumnsLayout" );
}


void AddresseeView::setColumnVisibility( int column, bool visible )
{
  if ( visible )
    showColumn( column );
  else
    hideColumn( column );
}

void AddresseeView::adjustColumn( int column )
{
  if ( column == Picture )
    {
      setColumnWidthMode( Picture, Manual );
      setColumnWidth( Picture, IMAGE_WIDTH );
    }
  else
    KListView::adjustColumn( column );
}

void AddresseeView::showColumn( int column )
{
  if ( ( column < 0 ) || ( column >= columns() ) )
    return;

  setColumnWidthMode( column, Maximum );
  adjustColumn( column );
  header()->setResizeEnabled( true, column );
}

void AddresseeView::hideColumn( int column )
{
  if ( ( column < 0 ) || ( column >= columns() ) )
    return;

  header()->setResizeEnabled( false, column );
  KListView::hideColumn( column );
  setColumnWidthMode( column, Manual );
}

KABC::Addressee AddresseeView::addressee( void )
{
  KABC::Addressee a;
  if ( selectionModeExt() == Single )
    {
      AddresseeItem *i = (AddresseeItem*)selectedItem();
      if ( i )
	a = i->addressee();
    }
  else
    {
      QListViewItemIterator it( this );
      for (; it.current(); it++ )
	{
	  AddresseeItem *i = (AddresseeItem*)*it;
	  if ( i->isSelected() )
	    {
	      a = i->addressee();
	      break;
	    }
	}
    }
  return a;
}

KABC::Addressee::List AddresseeView::addressees( void )
{
  KABC::Addressee::List al;

  if ( selectionModeExt() == Single )
    al.append( addressee() );
  else
    {
      QListViewItemIterator it( this );
      for (; it.current(); it++ )
	{
	  AddresseeItem *i = (AddresseeItem*)*it;
	  if ( i->isSelected() )
	    al.append( i->addressee() );
	}
    }
  return al;
}

bool AddresseeView::eventFilter( QObject *o, QEvent *e )
{
  if ( ( o == header() ) && ( e->type() == QEvent::MouseButtonPress ) )
    {
      QHeader *h = (QHeader *)o;
      QMouseEvent *me = (QMouseEvent *)e;
      if ( me->button() == Qt::RightButton )
	{
	  const int mouseOverColumn = h->sectionAt( me->pos().x() );

	  KPopupMenu m;
	  m.setCheckable( true );

	  if ( mouseOverColumn != -1 )
	    m.insertItem( i18n( "&Hide This Column" ), 0 );

	  int id = 1;
	  for ( int i=0; i < columns(); i++ )
	    {
	      int id = i+1;
	      m.insertItem( columnText( i ), id );
	      m.setItemChecked( id, columnWidth( i ) != 0 );
	    }
	  id ++;
	  m.insertTitle( i18n( "Columns" ), id, 1 );

	  id = m.exec( me->globalPos() );

	  if ( id == 0 )
	    hideColumn( mouseOverColumn );
	  else
	    {
	      int col = id - 1;
	      bool visible = !columnWidth( col );

	      setColumnVisibility( col, visible );
	      if ( ( col == Picture ) && visible )
		emit showPictures();

	      for ( int i=0; i < columns(); i++ )
		if ( columnWidth( i ) > 0 )
		  adjustColumn( i );
	    }

	  return true;
	}
    }
  return KListView::eventFilter( o, e );
}





/**
 * Addressee Item: a specialized KListViewItem that sets adressee fields.
 */
AddresseeItem::AddresseeItem( const KABC::Addressee &addressee,
			      AddresseeView *view,
			      bool loadImage ) :
  KListViewItem( view ), mAddressee( addressee )
{
  setMultiLinesEnabled( true );
  setColumns( loadImage );
}

KABC::Addressee AddresseeItem::addressee( void ) const
{
  return mAddressee;
}

void AddresseeItem::setColumns( bool loadImage )
{
  if ( loadImage )
    setImage();
  setWorkInfo();
  setText( AddresseeView::Name, mAddressee.realName() );
  setText( AddresseeView::PreferredEmail, mAddressee.preferredEmail() );
  setText( AddresseeView::Emails, mAddressee.emails().join( ",\n" ) );
  setPhones();
  setAddresses();
  setText( AddresseeView::Categories, mAddressee.categories().join( ",\n" ) );
}

void AddresseeItem::setWorkInfo( void )
{
  QStringList v;
  v.append( mAddressee.role() );
  v.append( mAddressee.organization() );
  setText( AddresseeView::WorkInfo, v.join( ",\n" ) );
}

void AddresseeItem::setImage( void )
{
  KABC::Picture picture = mAddressee.photo();
  QImage image;
  QString url;

  if ( picture.isIntern() )
    image = picture.data();
  else
    url = picture.url();

  if ( image.isNull() && url.isEmpty() )
    {
      picture = mAddressee.photo();
      if ( picture.isIntern() )
	image = picture.data();
      else
	url = picture.url();
    }

  if ( image.isNull() && url.isEmpty() )
    return;

  if ( image.isNull() )
    image = loadImage( KURL( url ) );

  if ( image.isNull() )
    return;

  if ( ( image.height() != IMAGE_HEIGHT ) ||
       ( image.width() != IMAGE_WIDTH ) )
    {
      if ( image.height() > image.width() )
	image = image.scaleHeight( IMAGE_HEIGHT );
      else
	image = image.scaleWidth( IMAGE_WIDTH );
    }

  setPixmap( AddresseeView::Picture, QPixmap( image ) );
}

void AddresseeItem::setPhones( void )
{
  QStringList phones, mobile, work, home, work_fax, home_fax;

  QString preferred;
  KABC::PhoneNumber::List pl = mAddressee.phoneNumbers();
  KABC::PhoneNumber::List::iterator pit;
  for ( pit = pl.begin(); pit != pl.end(); ++pit )
    {
      KABC::PhoneNumber phone = *pit;
      QString number = phone.number();
      phones.append( number );

      int type = phone.type();

      if ( ( type & KABC::PhoneNumber::Pref ) && ( preferred.isEmpty() ) )
	preferred = number;

      if ( type & KABC::PhoneNumber::Fax )
	{
	  if ( type & KABC::PhoneNumber::Home )
	    home_fax.append( number );
	  if ( type & KABC::PhoneNumber::Work )
	    work_fax.append( number );
	}
      else
	{
	  if ( type & KABC::PhoneNumber::Home )
	    home.append( number );
	  if ( type & KABC::PhoneNumber::Work )
	    work.append( number );
	  if ( type & KABC::PhoneNumber::Cell )
	    mobile.append( number );
	}
    }

  if ( preferred.isEmpty() )
    preferred = phones.first();

  setText( AddresseeView::PreferredPhone, preferred );
  setText( AddresseeView::Phones, phones.join( ",\n" ) );
  setText( AddresseeView::MobilePhone, mobile.join( ",\n" ) );
  setText( AddresseeView::HomePhone, home.join( ",\n" ) );
  setText( AddresseeView::HomeFax, home_fax.join( ",\n" ) );
  setText( AddresseeView::WorkPhone, work.join( ",\n" ) );
  setText( AddresseeView::WorkFax, work_fax.join( ",\n" ) );
}

void AddresseeItem::setAddresses( void )
{
  QString preferred;
  QStringList addresses, home, work;
  KABC::Address::List al = mAddressee.addresses();
  KABC::Address::List::iterator ait;
  for ( ait = al.begin(); ait != al.end(); ++ait )
    {
      KABC::Address address = *ait;
      addresses.append( address.formattedAddress() );

      int type = address.type();
      if ( ( type & KABC::Address::Pref ) && ( preferred.isEmpty() ) )
	preferred = address.formattedAddress();

      if ( type & KABC::Address::Home )
	home.append( address.formattedAddress() );
      if ( type & KABC::Address::Work )
	work.append( address.formattedAddress() );
    }

  if ( preferred.isEmpty() )
    preferred = addresses.first();

  setText( AddresseeView::PreferredAddress, preferred );
  setText( AddresseeView::Addresses, addresses.join( ",\n" ) );
  setText( AddresseeView::HomeAddress, home.join( ",\n" ) );
  setText( AddresseeView::WorkAddress, work.join( ",\n" ) );
}

QImage AddresseeItem::loadImage( const KURL &url )
{
  QString tempFile;
  QImage image;

  if ( url.isEmpty() )
    return image;

  if ( url.isLocalFile() )
    image = QImage( url.path() );
  else if ( KIO::NetAccess::download( url, tempFile, listView() ) )
    {
      image = QImage( tempFile );
      KIO::NetAccess::removeTempFile( tempFile );
    }

  if ( image.isNull() )
    {
      KMessageBox::sorry( listView(),
			  i18n( "Image of contact <b>%1</b> cannot "
				"be found." ).arg( mAddressee.realName() ) );
      return image;
    }

  return image;
}





/**
 * Adddressee Selector private data.
 */
class AddresseeSelector::AddresseeSelectorPrivate
{
public:
  AddresseeSelectorPrivate() :
    view( 0 ), searchLine( 0 ), addressbook( 0 )
  { }

  AddresseeView *view;
  KListViewSearchLineWidget *searchLine;
  KABC::AddressBook *addressbook;
};





/**
 * Addressee Selector: a widget with a ListView and a search bar.
 */
AddresseeSelector::AddresseeSelector( QWidget *parent,
				      const char *name ) :
  QFrame( parent, name ), d( 0 ), mLoadImages( false )
{
  init( KABC::StdAddressBook::self() );
}

AddresseeSelector::AddresseeSelector( KABC::AddressBook *addressbook,
				      QWidget *parent,
				      const char *name ) :
  QFrame( parent, name ), d( 0 ), mLoadImages( false )
{
  init( addressbook );
}

void AddresseeSelector::init( KABC::AddressBook *addressbook )
{
  if ( d )
    return;

  d = new AddresseeSelectorPrivate;
  d->view = new AddresseeView( this );
  d->searchLine = new KListViewSearchLineWidget( d->view, this );
  d->addressbook = addressbook;

  mLayout = new QVBoxLayout( this, 0, 3 );
  mLayout->addWidget( d->searchLine );
  mLayout->addWidget( d->view );

  connect( d->addressbook, SIGNAL( addressBookChanged( AddressBook *) ),
	   this, SLOT( addressBookChanged() ) );

  connect( d->view, SIGNAL( selectionChanged( QListViewItem * ) ),
	   this, SLOT( emitSelectionChanged( QListViewItem * ) ) );
  connect( d->view, SIGNAL( selectionChanged() ),
	   this, SLOT( emitSelectionChanged() ) );

  connect( d->view, SIGNAL( currentChanged( QListViewItem * ) ),
	   this, SLOT( emitCurrentChanged( QListViewItem * ) ) );

  connect( d->view, SIGNAL( clicked( QListViewItem * ) ),
	   this, SLOT( emitClicked( QListViewItem * ) ) );

  connect( d->view, SIGNAL( doubleClicked( QListViewItem * ) ),
	   this, SLOT( emitDoubleClicked( QListViewItem * ) ) );

  connect( d->view, SIGNAL( showPictures() ),
	   this, SLOT( showPictures() ) );
}

AddresseeSelector::~AddresseeSelector( void )
{
  delete d;
}

void AddresseeSelector::loadAddressBook( bool loadImages )
{
  mLoadImages = loadImages;
  d->addressbook->asyncLoad();
}

void AddresseeSelector::updateAddressees( void )
{
  d->view->clear();

  KABC::AddressBook::ConstIterator it = d->addressbook->begin();
  for (; it != d->addressbook->end(); it++ )
    {
      const KABC::Addressee contact = *it;
      new AddresseeItem( contact, d->view, mLoadImages );
    }
  setColumnVisibility( AddresseeView::Picture, mLoadImages );
}

void AddresseeSelector::addressBookChanged( void )
{
  updateAddressees();
}

void AddresseeSelector::showPictures( void )
{
  if ( ! mLoadImages )
    loadImages();
}

void AddresseeSelector::emitSelectionChanged( void )
{
  emit selectionChanged();
}

void AddresseeSelector::emitSelectionChanged( QListViewItem *i )
{
  emit selectionChanged( ((AddresseeItem*)i)->addressee() );
}

void AddresseeSelector::emitCurrentChanged( QListViewItem *i )
{
  emit currentChanged( ((AddresseeItem*)i)->addressee() );
}

void AddresseeSelector::emitClicked( QListViewItem *i )
{
  emit clicked( ((AddresseeItem*)i)->addressee() );
}

void AddresseeSelector::emitDoubleClicked( QListViewItem *i )
{
  emit doubleClicked( ((AddresseeItem*)i)->addressee() );
}

KABC::Addressee AddresseeSelector::addressee( void ) const
{
  return d->view->addressee();
}

KABC::Addressee::List AddresseeSelector::addressees( void ) const
{
  return d->view->addressees();
}

void AddresseeSelector::loadImages( void )
{
  mLoadImages = true;
  QListViewItemIterator it( d->view );
  for (; it.current(); it++ )
    {
      AddresseeItem *i = (AddresseeItem*)*it;
      i->setImage();
    }
  setColumnVisibility( AddresseeView::Picture, true );
}

void AddresseeSelector::unloadImages( void )
{
  mLoadImages = false;
  setColumnVisibility( AddresseeView::Picture, false );
}

AddresseeView *AddresseeSelector::view( void ) const
{
  return d->view;
}

void AddresseeSelector::setColumnVisibility( int column, bool visible )
{
  d->view->setColumnVisibility( column, visible );
}





/**
 * Utility to have a selector dialog
 */
AddresseeSelectorDialog::AddresseeSelectorDialog( QWidget *parent,
						  bool multiple,
						  bool loadImages ) :
  KDialogBase( KDialogBase::Plain, i18n("Select Addressee"),
	       Ok|Cancel, Ok, parent )
{
  mAddresseeSelector = new AddresseeSelector( plainPage() );
  init( loadImages, multiple );
}

AddresseeSelectorDialog::AddresseeSelectorDialog( KABC::AddressBook *ab,
						  QWidget *parent,
						  bool multiple,
						  bool loadImages ) :
  KDialogBase( KDialogBase::Plain, i18n("Select Addressee"),
	       Ok|Cancel, Ok, parent )
{
  mAddresseeSelector = new AddresseeSelector( ab, plainPage() );
  init( loadImages, multiple );
}

void AddresseeSelectorDialog::init( bool loadImages, bool multiple )
{
  QWidget *topWidget = plainPage();
  QBoxLayout *topLayout = new QVBoxLayout( topWidget );
  topLayout->addWidget( mAddresseeSelector );

  setInitialSize( QSize( 450, 300 ) );

  if ( multiple )
    mAddresseeSelector->view()->setSelectionModeExt( KListView::Multi );

  mAddresseeSelector->loadAddressBook( loadImages );
}

KABC::Addressee AddresseeSelectorDialog::addressee( void )
{
  return mAddresseeSelector->addressee();
}

KABC::Addressee::List AddresseeSelectorDialog::addressees( void )
{
  return mAddresseeSelector->addressees();
}

AddresseeSelectorDialog::~AddresseeSelectorDialog( void )
{
  delete mAddresseeSelector;
}

KABC::Addressee AddresseeSelectorDialog::getAddressee( QWidget *parent )
{
  AddresseeSelectorDialog *dlg = new AddresseeSelectorDialog( parent );
  KABC::Addressee addressee;
  int result = dlg->exec();

  if ( result == QDialog::Accepted )
    addressee = dlg->addressee();

  delete dlg;
  return addressee;
}

KABC::Addressee::List AddresseeSelectorDialog::getAddressees( QWidget *parent )
{
  AddresseeSelectorDialog *dlg = new AddresseeSelectorDialog( parent,
							      true );
  KABC::Addressee::List addressees;
  int result = dlg->exec();

  if ( result == QDialog::Accepted )
    addressees = dlg->addressees();

  delete dlg;
  return addressees;
}

