/***************************************************************************
                          winkswidget.cpp -  description
                             -------------------
    begin                : Sat Mar 8 2009
    copyright            : (C) 2009 by Antonio Nastasi
    email                : sifcenter (at) gmail.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 "winkswidget.h"

#include "../contact/msnobject.h"
#include "../utils/kmessconfig.h"
#include "../currentaccount.h"
#include "../kmessdebug.h"

#include <QDir>
#include <QDomDocument>
#include <QLabel>
#include <QListWidgetItem>
#include <QTextDocument>

#include <KIcon>
#include <KLocalizedString>
#include <KProcess>
#include <KStandardDirs>


WinksWidget::WinksWidget( QWidget *parent )
: QWidget(parent)
, noWinksWarning_(0)
{
  // Create and set the properties for list widget
  list_ = new QListWidget( this );
  list_->setViewMode( QListView::IconMode );
  list_->setResizeMode( QListView::Adjust );
  list_->setIconSize( QSize( 32,32 ) );
  list_->setMovement( QListView::Static );
  list_->setSelectionMode( QAbstractItemView::SingleSelection );
  list_->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
  list_->setFrameShape( QFrame::NoFrame );
  list_->setStyleSheet( "QListWidget { background-color: transparent; }" );

  winksDir_ = KMessConfig::instance()->getAccountsDirectory() + "/winks/";

  // Create an initial layout for the widget
  layout_ = new QBoxLayout( QBoxLayout::LeftToRight, this );
  layout_->setContentsMargins( 0,0,0,0 );
  layout_->setSpacing( 0 );
  layout_->addWidget( list_ );
}



WinksWidget::~WinksWidget()
{
  list_->clear();

  delete noWinksWarning_;
}



// Found better method to find out which winks is availables
// TODO may be we can create this cache one time and put one button to winks page to
// refresh this cache
void WinksWidget::refresh()
{
  list_->clear();
  const QDir directory( winksDir_, "*.cab" );
  QDir winkDirectory  ( winksDir_, "*.png" );
  QFileInfo fileInfo;
  KIcon icon;
  QString iconPath;
  const QStringList& cabFiles( directory.entryList( QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks ) );

  if( cabFiles.isEmpty() )
  {
    if( noWinksWarning_ == 0 )
    {
      // Create and set the properties for the warning message
      noWinksWarning_ = new QLabel( this );
      noWinksWarning_->setScaledContents( true );
      noWinksWarning_->setWordWrap( true );
      noWinksWarning_->setText( i18nc( "Informative label on the chat's winks bar",
                                    "<html><p><b>You do not have any winks yet.</b></p>"
                                    "<p>To add new ones, have your contacts send you some!</p></html>" ) );

      layout_->addWidget( noWinksWarning_ );
    }

    // Show the label and hide the list
    noWinksWarning_->show();
    list_->hide();

#ifdef KMESSDEBUG_WINKSWIDGET
    kDebug() << "There are no winks";
#endif
    return;
  }

  // If the label was created, hide it!
  if( noWinksWarning_ != 0 )
  {
    list_->show();
    noWinksWarning_->hide();
  }

  foreach( const QString& file, cabFiles )
  {
    // We need for file information to grep only it names ( without extension )
    fileInfo.setFile( winksDir_ + file );

    if( QFile::exists( winksDir_ + file + ".stamp" ) )
    {
      winkDirectory.setPath( winksDir_ + fileInfo.baseName() );
      // If the wink directory doens't exist we can't find the image of wink
      // so icon is set to one default
      // TODO we should try to extract the cab file to one directory so we be able to find the image
      if( ! winkDirectory.exists() )
      {
        iconPath = "view-media-artist";
      }
      else
      {
        // Search for wink image
        const QStringList& images( winkDirectory.entryList( QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks ) );
        if( images.isEmpty() )
        {
          iconPath = "view-media-artist";
        }
        else
        {
          iconPath = winkDirectory.path() + "/" + images.at(0);
        }
      }

      QString winkFriendly;
      QFile handle( winksDir_ + file + ".name" );
      if( handle.open( QIODevice::ReadOnly ) )
      {
        winkFriendly = handle.readAll();
        handle.close();
      }

      // Add the item
      QListWidgetItem *item = new QListWidgetItem( KIcon( iconPath ), "", list_ );
      item->setData( Qt::UserRole, file );
      item->setToolTip( winkFriendly );
    }
  }
}



//TODO clean this method
WinksWidget::CABEXTRACTOR WinksWidget::getHtmlFromWink( const QString &filename, QString &html )
{
  const QFileInfo fileInfo( filename );
  const QString& winksDir( KMessConfig::instance()->getAccountsDirectory() + "/winks/" + fileInfo.baseName() );

  QFile metaFile( winksDir +  + "/content.xml" );

  // See if the file was extracted already
  if( ! metaFile.exists() )
  {
    // Check if cabextract is installed
    if( KStandardDirs::findExe( "cabextract" ).isEmpty() )
    {
      return NOTINSTALLED;
    }

    // Run cabextract to get the contents of the file
    // -q: quiet, only print errors, -d: output dir, -l: force lowercase
    // (avoiding incompatibilities because win32 is case-insensitive)
    KProcess cabextract;
    cabextract.closeReadChannel( QProcess::StandardOutput );
    cabextract.setOutputChannelMode( KProcess::SeparateChannels );
    cabextract.setReadChannel( QProcess::StandardError );
    cabextract << "cabextract" << "-q" << "-d" << winksDir << filename;
    int exitCode = cabextract.execute( 5000 );
    // TODO: capture `cabextract` error messages, display nicely.

    if( exitCode != 0 )
    {
      const QByteArray& errorOutput( cabextract.readAll() );
      kWarning().nospace() << "cabextract failed with the following output: " << errorOutput.trimmed();

      return FAILED;
    }

    if( ! metaFile.exists() )
    {
      return UNKNOW;
    }
  }

  // Open the file
  if( ! metaFile.open( QIODevice::ReadOnly ) )
  {
    kWarning() << "file could not be opened: " << metaFile.fileName() << "!";
    return UNKNOW;
  }

  // Parse the XML
  QString xmlErrorMessage;
  QDomDocument xml;
  if( ! xml.setContent( &metaFile, true, &xmlErrorMessage ) )
  {
    kWarning() << "parsing of wink XML failed: " << xmlErrorMessage << "!";
    return UNKNOW;
  }

  // Get the package nodes
  const QDomElement& packageNode( xml.namedItem("package").toElement() );
  if( packageNode.isNull() )
  {
    kWarning() << "XML element /package not found!";
    return UNKNOW;
  }

  if( packageNode.attribute( "type" ) != "wink" )
  {
    kWarning() << "XML element /package/@type is not 'wink'!";
    return UNKNOW;
  }

  if( packageNode.attribute( "contenttype" ) != "D" )
  {
    kWarning() << "XML element /package/@contenttype is not 'D'!";
  }

  // Get the child nodes
  const QDomNodeList& packageItems( packageNode.childNodes() );
  QString thumbnail;
  QString animation;
  QString animationType;

  for(int i = 0; i < packageItems.count(); i++)
  {
    const QDomElement& child( packageItems.item(i).toElement() );
    if( child.tagName() == "item" )
    {
      const QString& type( child.attribute( "type" ) );
      if( type == "animation" )
      {
        animation = child.attribute( "file" );
        animationType = child.attribute( "mimetype" );
      }
      else if( type == "thumbnail-show" || type == "thumbnail" )
      {
        thumbnail = child.attribute( "file" );
        // Type not stored. There are winks with mimetype="image/png" while they're sending a JPG.
      }
      else
      {
        kWarning() << "unknown wink element type: '" << type << "'!";
      }
    }
  }

  if( thumbnail.isEmpty() || animation.isEmpty() || animationType.isEmpty() )
  {
    kWarning() << "XML elements are missing, could not play wink!";
    return UNKNOW;
  }

  // Escape data for inclusion in HTML.
  animation     = Qt::escape(animation).replace("\"", "&quot;");  // quotes are not escaped by QStyleSheet::escape().
  animationType = animationType.remove( QRegExp("[^a-zA-Z0-9\\-/]") );

  const QString& filePath( winksDir + "/" + animation );

  // Height of 150 is a lot, but most winks are designed to be full-screen, so they can hardly be displayed smaller.
  html = "<div class='winkContainer'>\n"
         "  <embed type=\"application/x-shockwave-flash\" src=\"" + filePath + "\" "
            "quality=\"autohigh\" wmode=\"transparent\" loop=\"false\" menu=\"false\" "
            "width=\"90%\" height=\"150\" />\n"
         "</div>\n";

  return SUCCESS;
}



const MsnObject WinksWidget::getMsnObjectWinkSelected()
{
  // Check if there is item selected
  QListWidgetItem *item = list_->currentItem();
  if( item == 0 )
  {
    return MsnObject();
  }

  // Grep the fileName of wink that the user selected and the handle to put in msn object
  const QString& fileName( item->data( Qt::UserRole).toString() );
  const QString&   handle( CurrentAccount::instance()->getHandle() );

  // First, check if the file exists
  QFile file( winksDir_ + fileName );
  if( ! file.open( QIODevice::ReadOnly ) )
  {
    return MsnObject();
  }

  // Create the fileInfo object to grep only name of file without extension
  const QFileInfo fileInfo( file );

  // Second, read the content of wink ( it will be used for compute sha1c in msnobject )
  const QByteArray& data( file.readAll() );
  file.close();

  // Try to read the certificate for the wink, without it the WLM doesn't show the wink received
  //TODO we could send it to no WLM client if the file( certificate ) isn't present....
  // I don't know which clients check for it
  file.setFileName( winksDir_ + fileName + ".stamp" );
  if( ! file.open( QIODevice::ReadOnly ) )
  {
    return MsnObject();
  }

  // Third, read the certificate
  const QByteArray& stamp( file.readAll() );
  file.close();
  if( stamp.isEmpty() )
  {
    return MsnObject();
  }

  // Then find out if the wink has a name
  QString winkFriendly;
  file.setFileName( winksDir_ + fileName + ".name" );
  if( file.open( QIODevice::ReadOnly ) )
  {
    winkFriendly = file.readAll();
    file.close();
  }

  // Finally, return the msn object
  return MsnObject( handle, fileInfo.baseName(), winkFriendly, MsnObject::WINK, data, stamp );
}



#include "winkswidget.moc"
