/***************************************************************************
                          contactsidebar.cpp  -  description
                             -------------------
    begin                : Thu Jan 16 2003
    copyright            : (C) 2003 by Mike K. Bennett
    email                : mkb137b@hotmail.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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "contactsidebar.h"

#include <qglobal.h>
#include <qlayout.h>
#include <qscrollview.h>
#include <qvbox.h>

#include <kdebug.h>

#include "../contact/contact.h"
#include "../contact/contactdrag.h"
#include "../contact/contactlist.h"
#include "../kmessdebug.h"
#include "invitedcontact.h"
#include "contactframe.h"

// The constructor
ContactSidebar::ContactSidebar(QWidget *parent, const char *name )
 : QScrollView(parent, name),
   contactList_(0)
{
  contactFrames_.setAutoDelete( true );

  // Create a widget to put the layout into (as we can't add layouts directly to scrollviews,
  //  nor make layouts the parents of widgets)
  viewBoxHolder_ = new QWidget( viewport(), "viewBoxHolder" );
  // Create a layout within the scrollview so that added widgets are laid out nicely
  viewBox_ = new QVBoxLayout( viewBoxHolder_, 0, -1, "viewBox" );
  // Set the view box's background color
  viewport()->setPaletteBackgroundColor( paletteBackgroundColor() );
  // turn on drops
  setAcceptDrops( true );
  viewport()->setAcceptDrops( true );
  // the drags to the sidebar don't have any requirement to be dropped on any specific frame
  //  so it's less annoying to the user if it doesn't scroll about the place while dragging.
  setDragAutoScroll( false );

  // put the viewBoxHolder (and hence the layout holding the frames) into the viewport
  addChild( viewBoxHolder_ );
}



// The destructor
ContactSidebar::~ContactSidebar()
{
}



// A contact joined the chat
void ContactSidebar::contactJoined(QString handle, QString friendlyName)
{
  ContactBase *contact;
  ContactFrame *contactFrame;
  // See if the contact already has a frame
  contactFrame = getContactFrameByHandle( handle );
  if ( contactFrame != 0 )
  {
    // Reactivate the contact's frame
    contactFrame->reactivate();
    return;
  }
  // Get the given contact
  contact = getContactByHandle( handle, friendlyName );
  if ( contact == 0 )
  {
    kdDebug() << "ContactSidebar::contactJoined() - Error finding contact " << handle << endl;
    return;
  }
  // Get the first available contact frame
  contactFrame = getFirstInactiveContactFrame();
  if ( contactFrame == 0 )
  {
    kdDebug() << "ContactSidebar::contactJoined() - No available contact frames for contact " << handle << "." << endl;
    return;
  }
  // Activate the frame
  contactFrame->activate( contact );
}



// A contact left the chat
void ContactSidebar::contactLeft(QString handle)
{
  ContactFrame *contactFrame = getContactFrameByHandle( handle );

  if ( contactFrame != 0 )
  {
    // deactivate (grey out) the contact frame
    contactFrame->deactivate();

    // the following code only works correctly on Qt > 3.1.0
    #if (QT_VERSION >= 0x030100)
    // frame is deactivated, so remove it from the layout
    viewBox_->remove( contactFrame );
    // and add it to the end of the layout
    viewBox_->insertWidget( -1, contactFrame );
    // ... this means that contacts in the chat move to the top,
    //  while others go to the bottom.
    #endif
  }
}



// A contact is typing
void ContactSidebar::contactTyping(QString handle, QString)
{
  ContactFrame *contactFrame = getContactFrameByHandle( handle );
  if ( contactFrame != 0 )
  {
    contactFrame->startTyping();
  }
}



// do we want this drop?
void ContactSidebar::contentsDropEvent( QDropEvent *event )
{
  if ( event->provides( ContactDragInfo::mimeType ) )
  {
    Contact *contact;

    contact = contactList_->getContactLastDragged();
    if (contact)
    {
      emit inviteContact( contact->getHandle() );
    }
  }

  event->ignore();
}



// something being dragged has entered our widget
void ContactSidebar::contentsDragEnterEvent( QDragEnterEvent *event )
{
  if ( event->provides( ContactDragInfo::mimeType ) )
  {
    event->accept( true );
  }
}



// something being dragged has been moved in our widget
void ContactSidebar::contentsDragMoveEvent( QDragMoveEvent *event )
{
  if ( event->provides( ContactDragInfo::mimeType ) )
  {
    event->acceptAction( true );
  }
}



// Find the contact with the given contact handle in the lists
ContactBase* ContactSidebar::getContactByHandle(QString handle, QString friendlyName)
{
#ifdef KMESSTEST
  ASSERT( contactList_ != 0 );
#endif
  // Check the contact list for the given contact
  if ( contactList_ != 0 )
  {
    Contact *contact = contactList_->getContactByHandle( handle );
    if ( contact != 0 )
    {
      return contact;
    }
  }

  // Check the invited contacts for the given contact
  for( InvitedContact *contact = invitedContacts_.first(); contact; contact = invitedContacts_.next() )
  {
    if ( contact->getHandle() == handle )
    {
      return contact;
    }
  }
  
  // If the contact wasn't found and the friendly name is not null..  (FIXME?)
  if ( friendlyName != "" )
  {
    // Create a new invited contact
    InvitedContact *contact = new InvitedContact( handle, friendlyName );
    invitedContacts_.append( contact );
    // Return the new contact
    return contact;
  }
  
  return 0;
}



// Find the contact frame with the given handle
ContactFrame* ContactSidebar::getContactFrameByHandle(const QString& handle)
{
  for ( ContactFrame *contactFrame = contactFrames_.first(); contactFrame; contactFrame = contactFrames_.next() )
  {
    if ( contactFrame->getHandle() == handle )
    {
      return contactFrame;
    }
  }
  return 0;
}



// Return the first inactive contact frame
ContactFrame* ContactSidebar::getFirstInactiveContactFrame()
{
  ContactFrame *contactFrame;
  for ( ContactFrame *contactFrame = contactFrames_.first(); contactFrame; contactFrame = contactFrames_.next() )
  {
    if ( !contactFrame->isActivated() )
    {
      return contactFrame;
    }
  }

  // Well we don't have any more, so make another.
  contactFrame = new ContactFrame( viewBoxHolder_, "frame" );
  // add it to the viewBox so it appears in the sidebar
  viewBox_->addWidget( contactFrame );
  // put it in the list of frames so we can find it again.
  contactFrames_.append( contactFrame );

  return contactFrame;
}



// Initialize the object
bool ContactSidebar::initialize()
{
  // The important frame-creating code has to go in the constructor, so there's less to initialize, here.

  return true;
}



// A message was received from one of the contacts... notify its frame
void ContactSidebar::messageReceived(const QString& handle)
{
  ContactFrame *frame;
  frame = getContactFrameByHandle( handle );
  if ( frame != 0 )
  {
    frame->messageReceived();
  }
}



// Set the contact list
void ContactSidebar::setContactList(ContactList *contactList)
{
  contactList_ = contactList;
}

#include "contactsidebar.moc"
