/*
 * This file Copyright (C) Mnemosyne LLC
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 * $Id: watchdir.cc 14150 2013-07-27 21:58:14Z jordan $
 */

#include <iostream>

#include <QDir>
#include <QFileSystemWatcher>
#include <QTimer>

#include <libtransmission/transmission.h>

#include "prefs.h"
#include "torrent-model.h"
#include "watchdir.h"

/***
****
***/

WatchDir :: WatchDir( const TorrentModel& model ):
    myModel( model ),
    myWatcher( 0 )
{
}

WatchDir :: ~WatchDir( )
{
}

/***
****
***/

int
WatchDir :: metainfoTest( const QString& filename ) const
{
    int ret;
    tr_info inf;
    tr_ctor * ctor = tr_ctorNew( 0 );

    // parse
    tr_ctorSetMetainfoFromFile( ctor, filename.toUtf8().constData() );
    const int err = tr_torrentParse( ctor, &inf );
    if( err )
        ret = ERROR;
    else if( myModel.hasTorrent( QString::fromUtf8( inf.hashString ) ) )
        ret = DUPLICATE;
    else
        ret = OK;

    // cleanup
    if( !err )
        tr_metainfoFree( &inf );
    tr_ctorFree( ctor );
    return ret;
}

void
WatchDir :: onTimeout( )
{
    QTimer * t = qobject_cast<QTimer*>(sender());
    const QString filename = t->objectName( );
    if( metainfoTest( filename ) == OK )
        emit torrentFileAdded( filename );
    t->deleteLater( );
}

void
WatchDir :: setPath( const QString& path, bool isEnabled )
{
    // clear out any remnants of the previous watcher, if any
    myWatchDirFiles.clear( );
    if( myWatcher ) {
        delete myWatcher;
        myWatcher = 0;
    }

    // maybe create a new watcher
    if( isEnabled ) {
        myWatcher = new QFileSystemWatcher( );
        myWatcher->addPath( path );
        connect( myWatcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(watcherActivated(const QString&)));
        //std::cerr << "watching " << qPrintable(path) << " for new .torrent files" << std::endl;
        watcherActivated( path ); // trigger the watchdir for .torrent files in there already
    }
}

void
WatchDir :: watcherActivated( const QString& path )
{
    const QDir dir(path);

    // get the list of files currently in the watch directory
    QSet<QString> files;
    foreach( QString str, dir.entryList( QDir::Readable|QDir::Files ) )
        files.insert( str );

    // try to add any new files which end in .torrent
    const QSet<QString> newFiles( files - myWatchDirFiles );
    const QString torrentSuffix = QString::fromUtf8( ".torrent" );
    foreach( QString name, newFiles ) {
        if( name.endsWith( torrentSuffix, Qt::CaseInsensitive ) ) {
            const QString filename = dir.absoluteFilePath( name );
            switch( metainfoTest( filename ) ) {
                case OK:
                    emit torrentFileAdded( filename );
                    break;
                case DUPLICATE:
                    break;
                case ERROR: {
                    // give the .torrent a few seconds to finish downloading
                    QTimer * t = new QTimer( this );
                    t->setObjectName( dir.absoluteFilePath( name ) );
                    t->setSingleShot( true );
                    connect( t, SIGNAL(timeout()), this, SLOT(onTimeout()));
                    t->start( 5000 );
                }
            }
        }
    }

    // update our file list so that we can use it
    // for comparison the next time around
    myWatchDirFiles = files;
}
