/*
 * This file is part of the KFTPGrabber project
 *
 * Copyright (C) 2003-2006 by the KFTPGrabber developers
 * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.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
 * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
 * NON-INFRINGEMENT.  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 Steet, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations
 * including the two.
 *
 * You must obey the GNU General Public License in all respects
 * for all of the code used other than OpenSSL.  If you modify
 * file(s) with this exception, you may extend this exception to your
 * version of the file(s), but you are not obligated to do so.  If you
 * do not wish to do so, delete this exception statement from your
 * version.  If you delete this exception statement from all source
 * files in the program, then also delete it here.
 */
#include "directoryscanner.h"
#include "kftpqueue.h"

#include "misc/config.h"
#include "misc/filter.h"

#include <kfileitem.h>

#include <qapplication.h>
#include <qdir.h>

using namespace KFTPQueue;
using namespace KFTPCore::Filter;
using namespace KFTPEngine;

DirectoryScanner::DirectoryScanner(Transfer *transfer)
{
  // Lock the transfer
  transfer->lock();
  
  // Construct a new thread and run it
  ScannerThread *thread = new ScannerThread(this, transfer);
  thread->start();
}

void DirectoryScanner::customEvent(QCustomEvent *e)
{
  if (e->type() == QS_THR_EVENT_ID) {
    KFTPQueue::Transfer *transfer = static_cast<KFTPQueue::Transfer*>(e->data());
    transfer->unlock();
    emit completed();
    
    // Destroy thiy object
    delete this;
  }
}

DirectoryScanner::ScannerThread::ScannerThread(QObject *parent, Transfer *item)
  : QThread(),
    m_parent(parent),
    m_item(item)
{
}

void DirectoryScanner::ScannerThread::run()
{
  // First scan the folder
  scanFolder(m_item);

  // We are done, post event to notify the GUI
  ScannerThreadEvent *e = new ScannerThreadEvent(m_item);
  qApp->postEvent(m_parent, e);
}

void DirectoryScanner::ScannerThread::scanFolder(Transfer *parent)
{
  QDir fs(parent->getSourceUrl().path());
  fs.setFilter(QDir::Readable | QDir::Hidden | QDir::All);

  const QFileInfoList *p_list = fs.entryInfoList();
  QFileInfoListIterator i(*p_list);
  QFileInfo *file;
  
  QValueList<DirectoryEntry> list;

  while ((file = i.current()) != 0) {
    ++i;

    if (file->fileName() == "." || file->fileName() == "..")
      continue;
    
    KURL sourceUrl;
    sourceUrl.setPath(file->absFilePath());

    // This is needed, since QFileInfo works with uint for the filesize
    filesize_t realSize = KFileItem(KFileItem::Unknown, KFileItem::Unknown, sourceUrl, true).size();
    
    // Check if we should skip this entry
    const ActionChain *actionChain = Filters::self()->process(sourceUrl, realSize, file->isDir());
     
    if (actionChain && actionChain->getAction(Action::Skip))
      continue;
    
    DirectoryEntry entry;
    entry.setFilename(file->fileName());
    entry.setType(file->isDir() ? 'd' : 'f');
    entry.setSize(realSize);
    
    list.append(entry);
  }
  
  // Sort by priority
  qHeapSort(list);
  
  QValueList<DirectoryEntry>::ConstIterator listEnd = list.end();
  for (QValueList<DirectoryEntry>::ConstIterator j = list.begin(); j != listEnd; ++j) {
    // Spawn transfer
    KURL destUrlBase = parent->getDestUrl();
    KURL sourceUrlBase = parent->getSourceUrl();
    
    destUrlBase.addPath((*j).filename());
    sourceUrlBase.addPath((*j).filename());
    
    if ((*j).isDirectory()) {
      // Directory
      qApp->lock();
      KFTPQueue::TransferDir *transfer = new KFTPQueue::TransferDir(parent);
      transfer->setSourceUrl(sourceUrlBase);
      transfer->setDestUrl(destUrlBase);
      transfer->addSize((*j).size());
      transfer->setTransferType(parent->getTransferType());
      transfer->setId(KFTPQueue::Manager::self()->nextTransferId());

      emit KFTPQueue::Manager::self()->newTransfer(transfer);
      qApp->unlock();

      // Call this function in recursion
      scanFolder(transfer);

      if (KFTPCore::Config::skipEmptyDirs() && !transfer->hasChildren()) {
        qApp->lock();
        KFTPQueue::Manager::self()->removeTransfer(transfer, false);
        qApp->unlock();
      }
    } else {
      // File
      qApp->lock();
      KFTPQueue::TransferFile *transfer = new KFTPQueue::TransferFile(parent);
      transfer->setSourceUrl(sourceUrlBase);
      transfer->setDestUrl(destUrlBase);
      transfer->addSize((*j).size());
      transfer->setTransferType(parent->getTransferType());
      transfer->setId(KFTPQueue::Manager::self()->nextTransferId());

      emit KFTPQueue::Manager::self()->newTransfer(transfer);
      qApp->unlock();
    }
  }
}

#include "directoryscanner.moc"


