/*
  IM address editor widget for KAddressBook

  Copyright (c) 2004 Will Stephenson   <lists@stevello.free-online.co.uk>

    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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of TQt, and distribute the resulting executable,
    without including the source code for TQt in the source distribution.
*/

#include <tqlistview.h>
#include <tqstringlist.h>
#include <tqvbox.h>
#include <tqlayout.h>
#include <tqfont.h>
#include <tqpainter.h>

#include <kdialogbase.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kplugininfo.h>
#include <kpushbutton.h>
#include <ktrader.h>

#include "imaddresswidget.h"
#include "imeditorbase.h"
#include "imeditorwidget.h"


IMAddressLVI::IMAddressLVI( TDEListView *parent, KPluginInfo *protocol,
                            const TQString &address, const IMContext &context )
  : TDEListViewItem( parent )
{
  setProtocol( protocol );
  setAddress( address );
  setContext( context );
  mPreferred = false;
}

void IMAddressLVI::setPreferred( bool preferred )
{
  mPreferred = preferred;
}

bool IMAddressLVI::preferred() const
{
  return mPreferred;
}

void IMAddressLVI::paintCell( TQPainter *p, const TQColorGroup &cg,
                              int column, int width, int alignment )
{
  if ( mPreferred ) {
    TQFont font = p->font();
    font.setBold( true );
    p->setFont( font );
  }

  TDEListViewItem::paintCell( p, cg, column, width, alignment );
}

void IMAddressLVI::setAddress( const TQString &address )
{
  // irc uses 0xE120 to seperate the nick and the server group.
  TQString serverOrGroup = address.section( TQChar( 0xE120 ), 1 );

  if ( serverOrGroup.isEmpty() )
    setText( 1, address );
  else {
    TQString nickname = address.section( TQChar( 0xE120 ), 0, 0 );
    setText( 1, i18n( "<nickname> on <server>","%1 on %2" )
           .arg( nickname ).arg( serverOrGroup ) );
  }

  mAddress = address;
}

void IMAddressLVI::setContext( const IMContext &context )
{
  mContext = context;
  // set context
/*  switch ( context )
  {
  case Home:
    setText( 2, i18n( "Home" ) );
    break;
  case Work:
    setText( 2, i18n( "Work" ) );
    break;
  case Any:
    setText( 2, i18n( "Any" ) );
    break;
  }
*/
}

void IMAddressLVI::setProtocol( KPluginInfo *protocol )
{
  mProtocol = protocol;

  setPixmap( 0, SmallIcon( mProtocol->icon() ) );
  setText( 0, mProtocol->name() );
}

KPluginInfo * IMAddressLVI::protocol() const
{
  return mProtocol;
}

IMContext IMAddressLVI::context() const
{
  return mContext;
}

TQString IMAddressLVI::address() const
{
  return mAddress;
}

void IMAddressLVI::activate()
{
  // show editor
}

/*===========================================================================*/

IMEditorWidget::IMEditorWidget( TQWidget *parent, const TQString &preferredIM, const char *name )
  : KDialogBase( parent, name, false, i18n( "Edit Instant Messenging Address" ),
                 Help | Ok | Cancel, Ok, false ),
    mReadOnly( false )
{
  mWidget = new IMEditorBase( this );
  setMainWidget( mWidget );

  connect( mWidget->btnAdd, TQ_SIGNAL( clicked() ), TQ_SLOT( slotAdd() ) );
  connect( mWidget->btnEdit, TQ_SIGNAL( clicked() ), TQ_SLOT( slotEdit() ) );
  connect( mWidget->btnDelete, TQ_SIGNAL( clicked() ), TQ_SLOT( slotDelete() ) );
  connect( mWidget->btnSetStandard, TQ_SIGNAL( clicked()), TQ_SLOT( slotSetStandard() ) );
  connect( mWidget->lvAddresses, TQ_SIGNAL( selectionChanged() ), TQ_SLOT( slotUpdateButtons() ) );

  connect( mWidget->lvAddresses, TQ_SIGNAL( doubleClicked( TQListViewItem*, const TQPoint&, int ) ),
           TQ_SLOT( slotEdit() ) );

  setHelp( "managing-contacts-im-addresses" );

  mWidget->btnEdit->setEnabled( false );
  mWidget->btnDelete->setEnabled( false );
  mWidget->btnSetStandard->setEnabled( false );
  // Disabled pending implementation
  //mWidget->btnUp->setEnabled( false );
  //mWidget->btnDown->setEnabled( false );
  mPreferred = preferredIM;
  mPreferred = mPreferred.replace( " on ", TQString( TQChar( 0xE120 ) ), true );
  mProtocols = KPluginInfo::fromServices( TDETrader::self()->query( TQString::fromLatin1( "KABC/IMProtocol" ) ) );

  // order the protocols by putting them in a qmap, then sorting the set of keys and recreating the list
  TQMap<TQString, KPluginInfo *> protocolMap;
  TQValueList<KPluginInfo *>::ConstIterator it;
  TQValueList<KPluginInfo *> sorted;
  for ( it = mProtocols.begin(); it != mProtocols.end(); ++it )
      protocolMap.insert( (*it)->name(), (*it) );

  TQStringList keys = protocolMap.keys();
  keys.sort();
  TQStringList::ConstIterator keyIt = keys.begin();	
  TQStringList::ConstIterator end = keys.end();
  for ( ; keyIt != end; ++keyIt )
      sorted.append( protocolMap[*keyIt] );
  mProtocols = sorted;
}

TQValueList<KPluginInfo *> IMEditorWidget::availableProtocols() const
{
  return mProtocols;
}

void IMEditorWidget::loadContact( TDEABC::Addressee *addr )
{
  if ( mWidget->lvAddresses )
    mWidget->lvAddresses->clear();

  // see README for details of how Evolution stores IM addresses (differently)
  const TQStringList customs = addr->customs();

  TQStringList::ConstIterator it;
  bool isSet = false;
  for ( it = customs.begin(); it != customs.end(); ++it ) {
    TQString app, name, value;
    splitField( *it, app, name, value );

    if ( app.startsWith( TQString::fromLatin1( "messaging/" ) ) ) {
      if ( name == TQString::fromLatin1( "All" ) ) {
        KPluginInfo *protocol = protocolFromString( app );
        if ( protocol ) {
          TQStringList addresses = TQStringList::split( TQChar( 0xE000 ), value );
          TQStringList::iterator end = addresses.end();
          for ( TQStringList::ConstIterator it = addresses.begin(); it != end; ++it ) {
            IMAddressLVI *imaddresslvi = new IMAddressLVI( mWidget->lvAddresses, protocol, *it, Any/*, false*/ );
            if ( !isSet && (*it).stripWhiteSpace().lower() == mPreferred.stripWhiteSpace().lower() ) {
              imaddresslvi->setPreferred( true );
              isSet = true;  //Only set one item to be preferred
            }
          }
        } else
          kdDebug( 5720 ) << k_funcinfo << " no protocol found for: " << app << endl;
      }
    }
  }

  if ( mWidget->lvAddresses->firstChild() )
    mWidget->lvAddresses->firstChild()->setSelected( true );
}

void IMEditorWidget::storeContact( TDEABC::Addressee *addr )
{
  // for each changed protocol, write a new custom field containing the current set of
  // addresses
  TQValueList<KPluginInfo *>::ConstIterator protocolIt;
  for ( protocolIt = mChangedProtocols.begin(); protocolIt != mChangedProtocols.end(); ++protocolIt ) {
    TQStringList lst;
    TQListViewItemIterator addressIt( mWidget->lvAddresses );
    while ( addressIt.current() ) {
      IMAddressLVI* currentAddress = static_cast<IMAddressLVI*>( *addressIt );
      if ( currentAddress->protocol() == *protocolIt )
        lst.append( currentAddress->address() );
      ++addressIt;
    }

    TQString addrBookField = (*protocolIt)->property( "X-TDE-InstantMessagingKABCField" ).toString();
    if ( !lst.isEmpty() )
      addr->insertCustom( addrBookField, TQString::fromLatin1( "All" ), lst.join( TQChar( 0xE000 ) ) );
    else
      addr->removeCustom( addrBookField, TQString::fromLatin1( "All" ) );
  }
}

void IMEditorWidget::setReadOnly( bool readOnly )
{
  mReadOnly = readOnly;
  slotUpdateButtons();
}

void IMEditorWidget::slotSetStandard()
{
  TQListViewItemIterator it( mWidget->lvAddresses, TQListViewItemIterator::Selected );

  // Just set the first one selected as standard
  if ( IMAddressLVI *current = static_cast<IMAddressLVI*>( it.current() ) ) {
    TQListViewItemIterator it2( mWidget->lvAddresses );
    while ( it2.current() ) {
      IMAddressLVI *item = static_cast<IMAddressLVI*>( it2.current() );

      if ( item->preferred() ) {
        if ( current == item )
          return; //Selected is already preferred
        else {
          item->setPreferred( false );
          mWidget->lvAddresses->repaintItem( item );
          break;
        }
      }

      ++it2;
    }

    mPreferred = current->address();
    current->setPreferred( true );
    setModified( true );
    mWidget->lvAddresses->repaintItem( current );
  }
}

void IMEditorWidget::slotUpdateButtons()
{
  int num_selected = 0;
  TQListViewItemIterator it( mWidget->lvAddresses, TQListViewItemIterator::Selected );
  while ( it.current() ) {
    ++num_selected;
    if ( num_selected > 1 )
      break; //no need to count above 2.

    ++it;
  }

  if ( !mReadOnly && num_selected == 1 ) {
    mWidget->btnAdd->setEnabled( true );
    mWidget->btnEdit->setEnabled( true );
    mWidget->btnDelete->setEnabled( true );
    IMAddressLVI *current = static_cast<IMAddressLVI*>( it.current() );

    // Disable "set standard" if already standard
    mWidget->btnSetStandard->setEnabled( !current || !current->preferred() );
  } else if ( !mReadOnly && num_selected > 1 ) {
    mWidget->btnAdd->setEnabled( true );
    mWidget->btnEdit->setEnabled( false );
    mWidget->btnDelete->setEnabled( true );
    mWidget->btnSetStandard->setEnabled( false );
  } else {
    mWidget->btnAdd->setEnabled( !mReadOnly );
    mWidget->btnSetStandard->setEnabled( false );
    mWidget->btnEdit->setEnabled( false );
    mWidget->btnDelete->setEnabled( false );
  }
}

void IMEditorWidget::setModified( bool modified )
{
  mModified = modified;
}

bool IMEditorWidget::isModified() const
{
  return mModified;
}

void IMEditorWidget::slotAdd()
{
  KDialogBase addDialog( this, "addaddress", true, i18n( "Instant messaging", "Add Address" ),
                         KDialogBase::Ok | KDialogBase::Cancel );

  IMAddressWidget *addressWid = new IMAddressWidget( &addDialog, mProtocols );
  addDialog.enableButtonOK( false );
  connect( addressWid, TQ_SIGNAL( inValidState( bool ) ),
           &addDialog, TQ_SLOT( enableButtonOK( bool ) ) );
  addDialog.setMainWidget( addressWid );

  if ( addDialog.exec() == TQDialog::Accepted ) {
    // add the new item
    IMAddressLVI *imaddresslvi = new IMAddressLVI( mWidget->lvAddresses, addressWid->protocol(),
                                                   addressWid->address() /*, addressWid->context() */ );

    // If it's a new address, set is as preferred.
    if ( mPreferred.isEmpty() ) {
      imaddresslvi->setPreferred( true );
      mPreferred = addressWid->address();
    }

    if ( mChangedProtocols.find( addressWid->protocol() ) == mChangedProtocols.end() )
      mChangedProtocols.append( addressWid->protocol() );

    mWidget->lvAddresses->sort();

    setModified( true );
  }
}

void IMEditorWidget::slotEdit()
{
  if( mReadOnly )
    return;
  TQListViewItemIterator it( mWidget->lvAddresses, TQListViewItemIterator::Selected );

  // Just edit the first one selected.
  if ( IMAddressLVI *current = static_cast<IMAddressLVI*>( it.current() ) ) {
    KDialogBase editDialog( this, "editaddress", true, i18n( "Instant messaging", "Edit Address" ),
                            KDialogBase::Ok | KDialogBase::Cancel );
    IMAddressWidget *addressWid = new IMAddressWidget( &editDialog, mProtocols, current->protocol(),
                                                       current->address(), current->context() ) ;
    connect( addressWid, TQ_SIGNAL( inValidState( bool ) ),
             &editDialog, TQ_SLOT( enableButtonOK( bool ) ) );
    editDialog.setMainWidget( addressWid );

    if ( editDialog.exec() == TQDialog::Accepted ) {
      bool modified = false;
      if ( addressWid->address() != current->address() ) {
        modified = true;
        current->setAddress( addressWid->address() );
      }
      if ( addressWid->context() != current->context() ) {
        modified = true;
        current->setContext( addressWid->context() );
      }

      // the entry for the protocol of the current address has changed
      if ( mChangedProtocols.find( current->protocol() ) == mChangedProtocols.end() ) {
        mChangedProtocols.append( current->protocol() );
      }
      // update protocol - has another protocol gained an address?
      if ( current->protocol() != addressWid->protocol() ) {
        modified = true;
        // this proto is losing an entry
        current->setProtocol( addressWid->protocol() );
        if ( mChangedProtocols.find( current->protocol() ) == mChangedProtocols.end() )
          mChangedProtocols.append( current->protocol() );
      }

      if ( modified )
        setModified(true);
    }
  }
}

void IMEditorWidget::slotDelete()
{
  int num_selected = 0;

  {
    TQListViewItemIterator it( mWidget->lvAddresses, TQListViewItemIterator::Selected );
    while ( it.current() ) {
      num_selected++;
      ++it;
    }
  }

  if ( num_selected == 0 )
    return;

  if ( KMessageBox::warningContinueCancel( this, i18n( "Do you really want to delete the selected address?",
                                           "Do you really want to delete the %n selected addresses?", num_selected ),
                                           i18n( "Confirm Delete" ), KStdGuiItem::del() ) != KMessageBox::Continue )
    return;

  TQListViewItemIterator it( mWidget->lvAddresses );
  bool deletedPreferred = false;
  while( it.current() ) {
    if ( it.current()->isSelected() ) {
      IMAddressLVI * current = static_cast<IMAddressLVI*>( *it );
      if ( mChangedProtocols.find( current->protocol() ) == mChangedProtocols.end() )
        mChangedProtocols.append( current->protocol() );

      if ( current->preferred() )
        deletedPreferred = true;

      delete current;
    } else
      ++it;
  }

  if ( deletedPreferred ) {
    IMAddressLVI *first = static_cast<IMAddressLVI*>( mWidget->lvAddresses->firstChild() );
    if ( first ) {
      first->setPreferred( true );
      mPreferred = first->address();
    } else
      mPreferred = "";
  }

  setModified( true );
}

TQString IMEditorWidget::preferred() const
{
  TQString retval( mPreferred );
  return retval.replace( TQChar( 0xE120 ), " on " );
}


KPluginInfo * IMEditorWidget::protocolFromString( const TQString &fieldValue ) const
{
  TQValueList<KPluginInfo *>::ConstIterator it;
  KPluginInfo * protocol = 0;
  for ( it = mProtocols.begin(); it != mProtocols.end(); ++it ) {
    if ( (*it)->property( "X-TDE-InstantMessagingKABCField" ).toString() == fieldValue ) {
      protocol = *it;
      break;
    }
  }

  return protocol;
}

void IMEditorWidget::splitField( const TQString &str, TQString &app, TQString &name, TQString &value )
{
  int colon = str.find( ':' );
  if ( colon != -1 ) {
    TQString tmp = str.left( colon );
    value = str.mid( colon + 1 );

    int dash = tmp.find( '-' );
    if ( dash != -1 ) {
      app = tmp.left( dash );
      name = tmp.mid( dash + 1 );
    }
  }
}

#include "imeditorwidget.moc"
