
#include <stdlib.h> 
#include <dlfcn.h>

#include <qdir.h>
#include <qframe.h>
#include <qregexp.h>
#include <qlayout.h>
#include <qcombobox.h>
#include <qpushbutton.h>

#include "testplugs.h"

namespace Plugin
{

TestPlugs::TestPlugs ( QWidget *pParent, const char *pName, bool bModal, WFlags fl )
    : uiMainForm ( pParent, pName, bModal, fl )
{
	m_iCurrentPlugin   =   -1;
	m_pLibrary         = NULL;
	m_pPlugin          = NULL;
	m_pDestroyFunction = NULL;
	m_pConfigWidget    = NULL;
	m_pLayoutMain = new QHBoxLayout ( m_pFrameMain, 11, 4 );

	connect ( m_pButtonCancel, SIGNAL ( clicked   (     ) ), this, SLOT ( slotCancel        (     ) ) );
	connect ( m_pButtonLoad,   SIGNAL ( clicked   (     ) ), this, SLOT ( slotLoad          (     ) ) );
	connect ( m_pComboPlugins, SIGNAL ( activated ( int ) ), this, SLOT ( slotPluginChanged ( int ) ) );
}

TestPlugs::~TestPlugs ( )
{
  unloadPlugin ( );
}

bool TestPlugs::loadPlugin ( uint iWhich )
{
  if ( iWhich > m_listOfPlugins.count ( ) )
    return false;

  QString qsFilePath = m_listOfPlugins[iWhich];

  m_pLibrary = dlopen ( qsFilePath.ascii ( ), RTLD_LAZY );
  if ( ! m_pLibrary ) {
    printf ( "Fatal: Cannot load library <%s>\n       %s\n", qsFilePath.ascii ( ), dlerror ( ) );
    return false;
  }

  // reset errors
  dlerror ( );

  // load the symbols
  create_t   *pCreateLibrary = (create_t *) dlsym ( m_pLibrary, "createPlugin" );
  const char *pErrorString   = dlerror (  );
  if ( pErrorString ) {
    printf ( "Cannot load symbol create: %s\n", pErrorString );
    return false;
  }

  m_pDestroyFunction = (destroy_t *) dlsym ( m_pLibrary, "destroyPlugin" );
  pErrorString = dlerror ( );
  if ( pErrorString ) {
    printf ( "Cannot load symbol destroy: %s\n", pErrorString );
    return false;
  }

  // create an instance of the class
  m_pPlugin = pCreateLibrary ( );

  if ( m_pPlugin )  {
    m_pConfigWidget = m_pPlugin->getConfigWidget ( m_pFrameMain );
    if ( m_pConfigWidget )  {
         m_pLayoutMain->addWidget ( m_pConfigWidget );
         m_pConfigWidget->show ( );
    }
  }

  m_iCurrentPlugin = iWhich;
  return true;
}

void TestPlugs::unloadPlugin ( )
{
  if ( m_pConfigWidget )
    delete m_pConfigWidget;
  m_pConfigWidget = NULL;

  // destroy the class
  if ( m_pPlugin && m_pDestroyFunction )  {
    m_pDestroyFunction ( m_pPlugin );
  }
  m_pDestroyFunction = NULL;
  m_pPlugin = NULL;

  // unload the triangle library
  if ( m_pLibrary )
    dlclose ( m_pLibrary );
  m_pLibrary = NULL;
}

void TestPlugs::initMe ( )
{
  uiMainForm::show ( );

  QString strDirectory   ( "../plugins" );
  int iRet = loadPlugins ( strDirectory );
  if ( iRet > 0 )  {
    loadPlugin ( 0 );
  }
}

void TestPlugs::slotCancel ( )
{
  uiMainForm::reject ( );
}

int TestPlugs::loadPlugins ( QString &strDirectory )
{
  QDir  theDir ( strDirectory );
  if ( !theDir.exists ( ) )  {
    printf ( "Fatal: Plugin directory <%s> does not exist.\n", strDirectory.ascii ( ) );
    return -1;
  }

  m_pComboPlugins->clear ( );

  theDir.setFilter  ( QDir::Files | QDir::Hidden );
  theDir.setSorting ( QDir::Reversed );
  const QFileInfoList *list = theDir.entryInfoList ( );
  QFileInfoListIterator it ( *list );
  QFileInfo *fi;
  QString qsFileName, qsFilePath;
  //QRegExp rx ( "*\\.so\\.*" ); all plugins
  QRegExp rx ( ".*\\.so$" );
  int iPluginCounter = 0;

  while ( ( fi = it.current   ( ) ) != 0 ) {
    qsFileName = fi->fileName ( );
    if ( qsFileName.find ( rx ) > -1 )  {
      qsFilePath = fi->filePath ( );
      // Okay so we have MyCreate *)pfound a library, lets check the interface ...
      void *pLibrary = dlopen ( qsFilePath.ascii ( ), RTLD_LAZY );
      if ( ! pLibrary ) {
        printf ( "Fatal: Cannot load library <%s>\n       %s\n", qsFilePath.ascii ( ), dlerror ( ) );
        return -1;
      }

      // reset errors
      dlerror ( );

      // load the symbols
      create_t   *pCreateLibrary = (create_t *) dlsym ( pLibrary, "createPlugin" );
      const char *pErrorString   = dlerror (  );
      if ( pErrorString ) {
        printf ( "Cannot load symbol create: %s\n", pErrorString );
        return -1;
      }

      destroy_t *pDestroyLibrary = (destroy_t *) dlsym ( pLibrary, "destroyPlugin" );
      pErrorString = dlerror ( );
      if ( pErrorString ) {
          printf ( "Cannot load symbol destroy: %s\n", pErrorString );
          return -1;
      }

      // create an instance of the class
      Interface *pPlugin = pCreateLibrary ( );

      // use the class
      if ( pPlugin )  {
        printf ( "SUCCESS : Plugin <%s> Name<%s>\n", qsFilePath.ascii ( ), pPlugin->getPluginName ( ).ascii ( ) );
        m_pComboPlugins->insertItem ( qsFileName );
        m_listOfPlugins .append     ( qsFilePath );
        iPluginCounter ++;
      }
      else
        printf ( "Could not create plugin %s\n", qsFilePath.ascii ( ) );
      // destroy the class
      pDestroyLibrary ( pPlugin );
      // unload the triangle library
      dlclose ( pLibrary );
    }
    ++it;
  }

  return iPluginCounter;
}

void TestPlugs::slotPluginChanged ( int iWhich )
{
  if ( iWhich == m_iCurrentPlugin )
    return;
  unloadPlugin ( );
  loadPlugin   ( iWhich );
}

void TestPlugs::slotLoad ( )
{
  // This function will pre-populate the structures for DVD creation.
  // Note: this is hardcoded stuff to files on my harddrive such as to test the plugin system
  // Once this is deemed usable I will continue work on the OneClickDVD wizrd and wrap up this
  // function.
//printf ( "Load Test data\n" );
  uint t, j;
  QDate date ( 2008,  1,  8 );
  QTime time (   12, 22, 44 );

  for ( t=0; t<10; t++ )  {
    SourceGroup *pGroup        = new SourceGroup;
    pGroup->enType             = SourceGroup::NTSC;
    pGroup->qsGroupName        = QString ( "Group %1" ).arg ( t );
    pGroup->qsScreenshot       = "/tmp/OneClick/screenshot.jpg";
    pGroup->bCreateChapterMenu = false;
    pGroup->bSlideshow         = false;
    pGroup->dateStart          = QDateTime ( date, time );
    date = date.addDays ( 10 );
    pGroup->dateEnd            = QDateTime ( date, time );

    for ( j=0; j<5; j++ )  {
      SourceGroup::SourceEntry *pEntry = new SourceGroup::SourceEntry;
      pEntry->iLength = (int) 448.820;
      pEntry->qsFileName.sprintf ( "/tmp/OneClick/vid%02d.mpg", t*5+j );
//printf ( "%s\n", pEntry->qsFileName.ascii ( ) );
    }
    if ( m_pPlugin )
         m_pPlugin->addGroup ( pGroup );
  }
  // Here we'll create the DVD
  if ( m_pPlugin )
       m_pPlugin->execute ( );
}

}; // end of namespace Plugin
