/***************************************************************************
    smb4ksearchdialog_part  -  This Part encapsulates the search dialog
    of Smb4K.
                             -------------------
    begin                : Fr Jun 1 2007
    copyright            : (C) 2007-2017 by Alexander Reinholdt
    email                : alexander.reinholdt@kdemail.net
 ***************************************************************************/

/***************************************************************************
 *   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, Suite 500, Boston,*
 *   MA 02110-1335, USA                                                    *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

// application specific includes
#include "smb4knetworksearch_part.h"
#include "smb4knetworksearch.h"
#include "smb4knetworksearchitem.h"
#include "core/smb4khost.h"
#include "core/smb4kshare.h"
#include "core/smb4ksettings.h"
#include "core/smb4kglobal.h"
#include "core/smb4kscanner.h"
#include "core/smb4kmounter.h"
#include "core/smb4ksearch.h"

// Qt includes
#include <QCoreApplication>
#include <QString>
#include <QKeySequence>
#include <QAction>
#include <QMenu>
#include <QLineEdit>

// KDE includes
#include <KCoreAddons/KPluginFactory>
#include <KCoreAddons/KAboutData>
#include <KWidgetsAddons/KDualAction>
#include <KWidgetsAddons/KGuiItem>
#include <KIconThemes/KIconLoader>
#include <KI18n/KLocalizedString>
#include <KXmlGui/KActionCollection>

using namespace Smb4KGlobal;

K_PLUGIN_FACTORY(Smb4KNetworkSearchPartFactory, registerPlugin<Smb4KNetworkSearchPart>();)


Smb4KNetworkSearchPart::Smb4KNetworkSearchPart(QWidget *parentWidget, QObject *parent, const QList<QVariant> &args)
: KParts::Part(parent), m_silent(false)
{
  // Parse arguments:
  for (int i = 0; i < args.size(); ++i)
  {
    if (args.at(i).toString().startsWith(QLatin1String("silent")))
    {
      if (QString::compare(args.at(i).toString().section('=', 1, 1).trimmed(), "\"true\"") == 0)
      {
        m_silent = true;
      }
      else
      {
        // Do nothing
      }
    }
    else
    {
      continue;
    }
  }
      
  // Set the XML file:
  setXMLFile("smb4knetworksearch_part.rc");

  // Set the widget of this part:
  m_widget = new Smb4KNetworkSearch(parentWidget);
  
  int icon_size = KIconLoader::global()->currentSize(KIconLoader::Small);
  m_widget->listWidget()->setIconSize(QSize(icon_size, icon_size));
  
  setWidget(m_widget);

  // Set up actions:
  setupActions();
  
  // Load the completion items.
  KConfigGroup group(Smb4KSettings::self()->config(), "SearchDialog");
  m_widget->comboBox()->completionObject()->setItems(group.readEntry("SearchItemCompletion", QStringList()));

  // Connections:
  connect(m_widget->comboBox(), SIGNAL(returnPressed()),
          this, SLOT(slotReturnPressed()));
  
  connect(m_widget->comboBox(), SIGNAL(editTextChanged(QString)),
          this, SLOT(slotComboBoxTextChanged(QString)));
  
  connect(m_widget->listWidget(), SIGNAL(itemDoubleClicked(QListWidgetItem*)),
          this, SLOT(slotItemDoubleClicked(QListWidgetItem*)));
  
  connect(m_widget->listWidget(), SIGNAL(itemSelectionChanged()),
          this, SLOT(slotItemSelectionChanged()));
  
  connect(m_widget->listWidget(), SIGNAL(customContextMenuRequested(QPoint)),
          this, SLOT(slotContextMenuRequested(QPoint)));
  
  connect(Smb4KMounter::self(), SIGNAL(mounted(SharePtr)),
          this, SLOT(slotShareMounted(SharePtr)));
  
  connect(Smb4KMounter::self(), SIGNAL(unmounted(SharePtr)),
          this, SLOT(slotShareUnmounted(SharePtr)));
  
  connect(Smb4KSearch::self(), SIGNAL(result(SharePtr)),
          this, SLOT(slotReceivedSearchResult(SharePtr)));
  
  connect(Smb4KSearch::self(), SIGNAL(aboutToStart(QString)),
          this, SLOT(slotSearchAboutToStart(QString)));
  
  connect(Smb4KSearch::self(), SIGNAL(finished(QString)),
          this, SLOT(slotSearchFinished(QString)));
  
  connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()),
          this, SLOT(slotAboutToQuit()));
  
  connect(KIconLoader::global(), SIGNAL(iconChanged(int)),
          this, SLOT(slotIconSizeChanged(int)));
}


Smb4KNetworkSearchPart::~Smb4KNetworkSearchPart()
{
}


void Smb4KNetworkSearchPart::setupActions()
{
  KDualAction *search_abort_action = new KDualAction(this);
  KGuiItem search_item(i18n("&Search"), KDE::icon("system-search"));
  KGuiItem abort_item(i18n("Abort"), KDE::icon("process-stop"));
  search_abort_action->setActiveGuiItem(search_item);
  search_abort_action->setInactiveGuiItem(abort_item);
  search_abort_action->setActive(true);
  search_abort_action->setAutoToggle(false);
  connect(search_abort_action, SIGNAL(triggered(bool)), this, SLOT(slotSearchAbortActionTriggered(bool)));
  connect(search_abort_action, SIGNAL(activeChanged(bool)), this, SLOT(slotSearchAbortActionChanged(bool)));
  
  QAction *clear_action  = new QAction(KDE::icon("edit-clear-history"), i18n("&Clear"), this);
  connect(clear_action, SIGNAL(triggered(bool)), this, SLOT(slotClearActionTriggered(bool)));

  KDualAction *mount_action = new KDualAction(this);
  KGuiItem mount_item(i18n("&Mount"), KDE::icon("media-mount"));
  KGuiItem unmount_item(i18n("&Unmount"), KDE::icon("media-eject"));
  mount_action->setActiveGuiItem(mount_item);
  mount_action->setInactiveGuiItem(unmount_item);
  mount_action->setActive(true);
  mount_action->setAutoToggle(false);
  connect(mount_action, SIGNAL(triggered(bool)), this, SLOT(slotMountActionTriggered(bool)));
  connect(mount_action, SIGNAL(activeChanged(bool)), this, SLOT(slotMountActionChanged(bool)));
  
  // Add the actions
  actionCollection()->addAction("search_abort_action", search_abort_action);
  actionCollection()->addAction("clear_search_action", clear_action);
  actionCollection()->addAction("mount_action", mount_action);
  
  // Set the shortcuts
  actionCollection()->setDefaultShortcut(search_abort_action, QKeySequence(Qt::CTRL+Qt::Key_S));
  actionCollection()->setDefaultShortcut(mount_action, QKeySequence(Qt::CTRL+Qt::Key_M));

  // Disable all actions.
  search_abort_action->setEnabled(false);
  clear_action->setEnabled(false);
  mount_action->setEnabled(false);

  // Put the actions in the context menu.
  m_menu = new KActionMenu(this);
  m_menu->addAction(clear_action);
  m_menu->addAction(mount_action);
  
  // Put some actions in the tool bar of the search widget
  m_widget->toolBar()->addAction(search_abort_action);
}


KAboutData *Smb4KNetworkSearchPart::createAboutData()
{
  KAboutData *aboutData = new KAboutData(QStringLiteral("smb4knetworksearchpart"), i18n("Smb4KNetworkSearchPart"),
    QStringLiteral("4.0"), i18n("The network search KPart of Smb4K"), KAboutLicense::GPL_V2, 
    i18n("\u00A9 2007-2015, Alexander Reinholdt"), QString(), QStringLiteral("http://smb4k.sourceforge.net"), 
    QStringLiteral("smb4k-bugs@lists.sourceforge.net"));

  return aboutData;
}


void Smb4KNetworkSearchPart::customEvent(QEvent *e)
{
  if (e->type() == Smb4KEvent::LoadSettings)
  {
    // The only changes may concern the marking of the shares.
    for (int i = 0; i < m_widget->listWidget()->count(); ++i)
    {
      Smb4KNetworkSearchItem *item = static_cast<Smb4KNetworkSearchItem *>(m_widget->listWidget()->item(i));
    
      switch (item->type())
      {
        case Smb4KNetworkSearchItem::Share:
        {
          // First update the share.
          item->update();
            
          // Now either mark it again or leave it unmarked.
          QList<SharePtr> list = findShareByUNC(item->shareItem()->unc());
          
          for (const SharePtr &share : list)
          {
            if (share->isMounted())
            {
              slotShareMounted(share);
               
              if (!share->isForeign())
              {
                break;
              }
              else
              {
                continue;
              }
            }
            else
            {
              continue;
            }
          }
        }
        default:
        {
          break;
        }
      }        
    }
  }
  else if (e->type() == Smb4KEvent::SetFocus)
  {
    m_widget->comboBox()->lineEdit()->setFocus();
  }
  else if (e->type() == Smb4KEvent::MountOrUnmountShare)
  {
    // Change the active state of the mount action. This needs
    // to be done here, because the action is not switched
    // automatically in case the part is notified from outside.
    KDualAction *mount_action = static_cast<KDualAction *>(actionCollection()->action("mount_action"));
    mount_action->setActive(!mount_action->isActive());

    // Mount or unmount the share.
    slotMountActionTriggered(false);
  }
  else
  {
    // Do nothing
  }

  KParts::Part::customEvent(e);
}


/////////////////////////////////////////////////////////////////////////////
// SLOT IMPLEMENTATIONS (Smb4KNetworkSearchPart)
/////////////////////////////////////////////////////////////////////////////

void Smb4KNetworkSearchPart::slotReturnPressed()
{
  if (!m_widget->comboBox()->currentText().isEmpty())
  {
    KDualAction *search_abort_action = static_cast<KDualAction *>(actionCollection()->action("search_abort_action"));
    
    if (search_abort_action && search_abort_action->isActive())
    {
      slotSearchAbortActionTriggered(false);
    }
    else
    {
      // Do nothing
    }
  }
  else
  {
    // Do nothing
  }
}


void Smb4KNetworkSearchPart::slotSearchAbortActionTriggered(bool /*checked*/)
{
  KDualAction *search_abort_action = static_cast<KDualAction *>(actionCollection()->action("search_abort_action"));
  
  if (search_abort_action)
  {
    if (search_abort_action->isActive())
    {
      // Start the search.
      m_widget->listWidget()->clear();

      QString search_item = m_widget->comboBox()->currentText();

      if (!search_item.isEmpty())
      {
        Smb4KSearch::self()->search(m_widget->comboBox()->currentText(), m_widget);
        KCompletion *completion = m_widget->comboBox()->completionObject();
        completion->addItem(search_item);
      }
      else
      {
        // Do nothing
      }
    }
    else
    {
      QString search_item = m_widget->comboBox()->currentText();
    
      if (!search_item.isEmpty())
      {
        Smb4KSearch::self()->abort(m_widget->comboBox()->currentText());
      }
      else
      {
        // Do nothing
      }
    }
  }
  else
  {
    // Do nothing
  }
}


void Smb4KNetworkSearchPart::slotSearchAbortActionChanged(bool active)
{
  if (active)
  {
    QAction *search_abort_action = actionCollection()->action("search_abort_action");
    actionCollection()->setDefaultShortcut(search_abort_action, QKeySequence(Qt::CTRL+Qt::Key_S));
  }
  else
  {
    QAction *search_abort_action = actionCollection()->action("search_abort_action");
    actionCollection()->setDefaultShortcut(search_abort_action, QKeySequence(Qt::CTRL+Qt::Key_A));
  }
}


void Smb4KNetworkSearchPart::slotClearActionTriggered(bool /*checked*/)
{
  // Clear the combo box and the list widget.
  m_widget->comboBox()->clear();
  m_widget->comboBox()->clearEditText();
  m_widget->listWidget()->clear();

  // Disable the actions.
  actionCollection()->action("search_abort_action")->setEnabled(false);
  actionCollection()->action("clear_search_action")->setEnabled(false);
  actionCollection()->action("mount_action")->setEnabled(false);
}


void Smb4KNetworkSearchPart::slotMountActionTriggered(bool /*checked*/)
{
  // Check if we need to add this host to the global list of hosts.
  Smb4KNetworkSearchItem *searchItem = static_cast<Smb4KNetworkSearchItem *>(m_widget->listWidget()->currentItem());

  switch (searchItem->type())
  {
    case Smb4KNetworkSearchItem::Share:
    {
      if (!searchItem->shareItem()->isMounted())
      {
        Smb4KMounter::self()->mountShare(searchItem->shareItem(), m_widget);
      }
      else
      {
        Smb4KMounter::self()->unmountShare(searchItem->shareItem(), false, m_widget);
      }
      break;
    }
    default:
    {
      break;
    }
  }
}


void Smb4KNetworkSearchPart::slotMountActionChanged(bool active)
{
  if (active)
  {
    QAction *mount_action = actionCollection()->action("mount_action");
    actionCollection()->setDefaultShortcut(mount_action, QKeySequence(Qt::CTRL+Qt::Key_M));
  }
  else
  {
    QAction *mount_action = actionCollection()->action("mount_action");
    actionCollection()->setDefaultShortcut(mount_action, QKeySequence(Qt::CTRL+Qt::Key_U));
  }
}


void Smb4KNetworkSearchPart::slotComboBoxTextChanged(const QString &text)
{
  actionCollection()->action("search_abort_action")->setEnabled(!text.isEmpty());
  actionCollection()->action("clear_search_action")->setEnabled(!text.isEmpty());
}


void Smb4KNetworkSearchPart::slotItemDoubleClicked(QListWidgetItem *item)
{
  if (item)
  {
    // If we have got an item, enable the "Add" button if the
    // item is regular. Otherwise disable the button.
    Smb4KNetworkSearchItem *searchItem = static_cast<Smb4KNetworkSearchItem *>(item);

    switch (searchItem->type())
    {
      case Smb4KNetworkSearchItem::Share:
      {
        if (!searchItem->shareItem()->isMounted())
        {
          Smb4KMounter::self()->mountShare(searchItem->shareItem(), m_widget);
        }
        else
        {
          Smb4KMounter::self()->unmountShare(searchItem->shareItem(), false, m_widget);
        }
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else
  {
    // Do nothing
  }
}


void Smb4KNetworkSearchPart::slotItemSelectionChanged()
{
  QList<QListWidgetItem *> list = m_widget->listWidget()->selectedItems();

  if (!list.isEmpty())
  {
    // We are in single selection mode, so there is only one
    // item in the list.
    if (list.count() == 1)
    {
      Smb4KNetworkSearchItem *searchItem = static_cast<Smb4KNetworkSearchItem *>(list.first());

      switch (searchItem->type())
      {
        case Smb4KNetworkSearchItem::Share:
        {
          if (!searchItem->shareItem()->isMounted() || (searchItem->shareItem()->isMounted() && searchItem->shareItem()->isForeign()))
          {
            actionCollection()->action("mount_action")->setEnabled(true);
            static_cast<KDualAction *>(actionCollection()->action("mount_action"))->setActive(true);
          }
          else if (searchItem->shareItem()->isMounted() && !searchItem->shareItem()->isForeign())
          {
            actionCollection()->action("mount_action")->setEnabled(true);
            static_cast<KDualAction *>(actionCollection()->action("mount_action"))->setActive(false);
          }
          else
          {
            actionCollection()->action("mount_action")->setEnabled(false);
            static_cast<KDualAction *>(actionCollection()->action("mount_action"))->setActive(true);
          }
          
          break;
        }
        default:
        {
          actionCollection()->action("mount_action")->setEnabled(false);
          static_cast<KDualAction *>(actionCollection()->action("mount_action"))->setActive(true);
          break;
        }
      }
    }
    else
    {
      actionCollection()->action("mount_action")->setEnabled(false);
      static_cast<KDualAction *>(actionCollection()->action("mount_action"))->setActive(true);
    }
  }
  else
  {
    actionCollection()->action("mount_action")->setEnabled(false);
    static_cast<KDualAction *>(actionCollection()->action("mount_action"))->setActive(true);
  }
}


void Smb4KNetworkSearchPart::slotContextMenuRequested(const QPoint &pos)
{
  Smb4KNetworkSearchItem *item = static_cast<Smb4KNetworkSearchItem *>(m_widget->listWidget()->itemAt(pos));

  if (item)
  {
    switch (item->type())
    {
      case Smb4KNetworkSearchItem::Share:
      {
        m_menu->menu()->setTitle(item->shareItem()->unc());
        m_menu->menu()->setIcon(item->icon());
        break;
      }
      default:
      {
        m_menu->menu()->setTitle(i18n("Search Results"));
        m_menu->menu()->setIcon(KDE::icon("system-search"));
        break;
      }
    }
  }
  else
  {
    m_menu->menu()->setTitle(i18n("Search Results"));
    m_menu->menu()->setIcon(KDE::icon("system-search"));
  }

  m_menu->menu()->popup(m_widget->listWidget()->viewport()->mapToGlobal(pos));
}


void Smb4KNetworkSearchPart::slotReceivedSearchResult(const SharePtr &share)
{
  Q_ASSERT(share);

  // Create a Smb4KNetworkSearchItem and add it to the first position.
  (void) new Smb4KNetworkSearchItem(m_widget->listWidget(), share);

  m_widget->listWidget()->sortItems();

  // Enable the combo box and set the focus:
  m_widget->comboBox()->setEnabled(true);
  m_widget->comboBox()->setFocus();

  // Now select the text, so that the user can easily
  // remove it.
  m_widget->comboBox()->lineEdit()->selectAll();
}


void Smb4KNetworkSearchPart::slotSearchAboutToStart(const QString &string)
{
  if (!m_silent)
  {
    emit setStatusBarText(i18n("Searching for \"%1\"...", string));
  }
  else
  {
    // Do nothing
  }

  m_widget->comboBox()->setEnabled(false);
  KDualAction *search_abort_action = static_cast<KDualAction *>(actionCollection()->action("search_abort_action"));
  
  if (search_abort_action)
  {
    search_abort_action->setActive(false);
  }
  else
  {
    // Do nothing
  }
  
  actionCollection()->action("clear_search_action")->setEnabled(false);
  // Add action will be disabled elsewhere.
}


void Smb4KNetworkSearchPart::slotSearchFinished(const QString &/*string*/)
{
  if (!m_silent)
  {
    emit setStatusBarText(i18n("Done."));
  }
  else
  {
    // Do nothing
  }

  m_widget->comboBox()->setEnabled(true);
  KDualAction *search_abort_action = static_cast<KDualAction *>(actionCollection()->action("search_abort_action"));
  
  if (search_abort_action)
  {
    search_abort_action->setActive(true);
  }
  else
  {
    // Do nothing
  }
  
  actionCollection()->action("clear_search_action")->setEnabled(!m_widget->comboBox()->currentText().isEmpty());

  if (m_widget->listWidget()->count() == 0)
  {
    new Smb4KNetworkSearchItem(m_widget->listWidget());
  }
  else
  {
    // Do nothing
  }
}


void Smb4KNetworkSearchPart::slotShareMounted(const SharePtr &share)
{
  Q_ASSERT(share);
  
  for (int i = 0; i < m_widget->listWidget()->count(); ++i)
  {
    Smb4KNetworkSearchItem *searchItem = static_cast<Smb4KNetworkSearchItem *>(m_widget->listWidget()->item(i));
    
    switch (searchItem->type())
    {
      case Smb4KNetworkSearchItem::Share:
      {
        if (QString::compare(searchItem->shareItem()->unc(), share->unc(), Qt::CaseInsensitive) == 0)
        {
          searchItem->update();
        }
        else
        {
          // Do nothing
        }
        break;
      }
      default:
      {
        break;
      }
    }
  }
}


void Smb4KNetworkSearchPart::slotShareUnmounted(const SharePtr &share)
{
  Q_ASSERT(share);
  
  for (int i = 0; i < m_widget->listWidget()->count(); ++i)
  {
    Smb4KNetworkSearchItem *item = static_cast<Smb4KNetworkSearchItem *>(m_widget->listWidget()->item(i));
    
    switch (item->type())
    {
      case Smb4KNetworkSearchItem::Share:
      {
        if (QString::compare(item->shareItem()->unc(), share->unc(), Qt::CaseInsensitive) == 0)
        {
          item->update();
        }
        else
        {
          // Do nothing
        }
        break;
      }
      default:
      {
        break;
      }
    }
  }
}


void Smb4KNetworkSearchPart::slotAboutToQuit()
{
  KConfigGroup group(Smb4KSettings::self()->config(), "SearchDialog");
  group.writeEntry("SearchItemCompletion", m_widget->comboBox()->completionObject()->items());
}


void Smb4KNetworkSearchPart::slotIconSizeChanged(int group)
{
  switch (group)
  {
    case KIconLoader::Small:
    {
      int icon_size = KIconLoader::global()->currentSize(KIconLoader::Small);
      m_widget->listWidget()->setIconSize(QSize(icon_size, icon_size));
      break;
    }
    default:
    {
      break;
    }
  }
}


void Smb4KNetworkSearchPart::slotMounterFinished(const SharePtr &, int process)
{
  switch (process)
  {
    case MountShare:
    {
      KDualAction *mount_action = static_cast<KDualAction *>(actionCollection()->action("mount_action"));
      
      if (mount_action)
      {
        mount_action->setActive(false);
      }
      else
      {
        // Do nothing
      }
      break;
    }
    case UnmountShare:
    {
      KDualAction *mount_action = static_cast<KDualAction *>(actionCollection()->action("mount_action"));
      
      if (mount_action)
      {
        mount_action->setActive(true);
      }
      else
      {
        // Do nothing
      }
      break;
    }
    default:
    {
      break;
    }
  }
}

#include "smb4knetworksearch_part.moc"
