/*
 * This file Copyright (C) 2009 Charles Kerr <charles@transmissionbt.com>
 *
 * This file is licensed by the GPL version 2.  Works owned by the
 * Transmission project are granted a special exemption to clause 2(b)
 * so that the bulk of its code can remain under the MIT license.
 * This exemption does not extend to derived works not owned by
 * the Transmission project.
 *
 * $Id: make-dialog.cc 8570 2009-05-31 19:33:48Z charles $
 */

#include <cassert>
#include <iostream>

#include <QDialogButtonBox>
#include <QTimer>
#include <QFileDialog>
#include <QLabel>
#include <QStyle>
#include <QPushButton>
#include <QLineEdit>
#include <QPlainTextEdit>
#include <QCheckBox>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QList>
#include <QProgressBar>

#include <libtransmission/transmission.h>
#include <libtransmission/makemeta.h>
#include <libtransmission/utils.h>

#include "hig.h"
#include "make-dialog.h"
#include "squeezelabel.h"
#include "qticonloader.h"
#include "utils.h"

MakeDialog :: MakeDialog( Session & mySession, QWidget * parent ):
    QDialog( parent, Qt::Dialog ),
    myBuilder( 0 ),
    myIsBuilding( 0 )
{
    Q_UNUSED( mySession );
    connect( &myTimer, SIGNAL(timeout()), this, SLOT(onProgress()) );

    setWindowTitle( tr( "New Torrent" ) );
    QVBoxLayout * top = new QVBoxLayout( this );
    top->setSpacing( HIG :: PAD );

    HIG * hig = new HIG;
    hig->setContentsMargins( 0, 0, 0, 0 );
    hig->addSectionTitle( tr( "Source" ) );
    hig->addWideControl( mySourceEdit = new QLineEdit );
    connect( mySourceEdit, SIGNAL(textChanged(const QString&)), this, SLOT(refresh()));
    connect( mySourceEdit, SIGNAL(editingFinished()), this, SLOT(onSourceChanged()));
    QHBoxLayout * h = new QHBoxLayout;
    h->setContentsMargins( 0, 0, 0, 0 );
    h->addWidget( mySourceLabel = new QLabel( tr( "<i>No source selected</i>" ) ) );
    mySourceLabel->setMinimumWidth( fontMetrics().size( 0, "420 KB in 412 Files; 402 Pieces @ 42 KB each" ).width( ) );
    h->addStretch( 1 );
    h->setSpacing( HIG :: PAD );
    QPushButton * b = new QPushButton( style()->standardIcon( QStyle::SP_DirIcon ), tr( "F&older" ) );
    connect( b, SIGNAL(clicked(bool)), this, SLOT(onFolderButtonPressed()));
    h->addWidget( b );
    b = new QPushButton( style()->standardIcon( QStyle::SP_FileIcon ), tr( "&File" ) );
    connect( b, SIGNAL(clicked(bool)), this, SLOT(onFileButtonPressed()));
    h->addWidget( b );
    hig->addWideControl( h );
    hig->addSectionDivider( );
    hig->addSectionTitle( tr( "Trackers" ) );
    hig->addWideControl( myTrackerEdit = new QPlainTextEdit );
    connect( myTrackerEdit, SIGNAL(textChanged()), this, SLOT(refresh()) );
    const int height = fontMetrics().size( 0, "\n\n\n\n" ).height( );
    myTrackerEdit->setMinimumHeight( height );
    myTrackerEdit->setMaximumHeight( height );
    hig->addWideControl( new QLabel( tr( "Separate tiers with an empty line" ) ) );
    hig->addSectionDivider( );
    hig->addSectionTitle( tr( "Options" ) );
    hig->addRow( tr( "Commen&t:" ), myCommentEdit = new QLineEdit );
    hig->addWideControl( myPrivateCheck = new QCheckBox( "&Private torrent" ) );
    hig->addSectionDivider( );
    hig->addSectionDivider( );
    hig->addSectionTitle( tr( "Progress" ) );
    QProgressBar * p = myProgressBar = new QProgressBar;
    p->setTextVisible( false );
    p->setMinimum( 0 );
    p->setMaximum( 100 );
    p->setValue( 0 );
    hig->addWideControl( p );
    hig->addWideControl( myProgressLabel = new QLabel( "<i>No source selected</i>" ) );
    hig->finish( );
    top->addWidget( hig, 1 );

    //QFrame * f = new QFrame;
    //f->setFrameShape( QFrame :: HLine );
    //top->addWidget( f );


    QIcon icon;
    QDialogButtonBox * buttons = new QDialogButtonBox( this );

    icon = style()->standardIcon( QStyle::SP_FileDialogNewFolder );
    icon = QtIconLoader :: icon( "document-new", icon );
    b = myMakeButton = new QPushButton( icon, tr( "&New Torrent" ) );
    buttons->addButton( b, QDialogButtonBox::ActionRole );

    icon = style()->standardIcon( QStyle::SP_DialogCancelButton );
    icon = QtIconLoader :: icon( "process-stop", icon );
    b = myStopButton = new QPushButton( icon, tr( "&Stop" ) );
    buttons->addButton( b, QDialogButtonBox::RejectRole );

    icon = style()->standardIcon( QStyle::SP_DialogCloseButton );
    icon = QtIconLoader :: icon( "window-close", icon );
    b = myCloseButton = new QPushButton( icon, tr( "&Close" ) );
    buttons->addButton( b, QDialogButtonBox::AcceptRole );

    connect( buttons, SIGNAL(clicked(QAbstractButton*)),
             this, SLOT(onButtonBoxClicked(QAbstractButton*)) );

    top->addWidget( buttons );
    refresh( );
}

MakeDialog :: ~MakeDialog( )
{
    if( myBuilder )
        tr_metaInfoBuilderFree( myBuilder );
}

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

QString
MakeDialog :: getResult( ) const
{
    QString str;

    switch( myBuilder->result )
    {
        case TR_MAKEMETA_OK:
            str = tr( "%1.torrent created!" ).arg( myBuilder->top );
            break;

        case TR_MAKEMETA_URL:
            str = tr( "Error: Invalid URL" );
            break;

        case TR_MAKEMETA_CANCELLED:
            str = tr( "Torrent creation cancelled" );
            break;

        case TR_MAKEMETA_IO_READ:
            str = tr( "Error: Couldn't read \"%1\": %2" )
                     .arg( myBuilder->errfile )
                     .arg( tr_strerror( myBuilder->my_errno ) );
            break;

        case TR_MAKEMETA_IO_WRITE:
            str = tr( "Error: Couldn't create \"%1\": %2" )
                     .arg( myBuilder->errfile )
                     .arg( tr_strerror( myBuilder->my_errno ) );
            break;
    }

    return str;
}

void
MakeDialog :: refresh( )
{
    QString progressText;
    bool canBuild = true;

    if( myIsBuilding ) {
        progressText = tr( "Creating %1.torrent" ).arg( myBuilder->top );
        canBuild = false;
    } else if( mySourceEdit->text().trimmed().isEmpty() ) {
        progressText = tr( "<i>No source selected<i>" );
        canBuild = false;
    } else if( myTrackerEdit->toPlainText().isEmpty() ) {
        progressText = tr( "<i>No tracker announce URLs listed</i>" );
        canBuild = false;
    } else if( myBuilder && myBuilder->isDone ) {
        progressText = getResult( );
        canBuild = true;
    }

    myProgressLabel->setText( progressText );
    myMakeButton->setEnabled( canBuild && myBuilder );
    myCloseButton->setEnabled( !myIsBuilding );
    myStopButton->setEnabled( myIsBuilding );
}

void
MakeDialog :: setIsBuilding( bool isBuilding )
{
    myIsBuilding = isBuilding;

    if( myBuilder )
        myBuilder->result = TR_MAKEMETA_OK;

    if( isBuilding )
        myProgressBar->setValue( 0 );

    if( isBuilding )
        myTimer.start( 100 );
    else
        myTimer.stop( );

    refresh( );
}

void
MakeDialog :: onProgress( )
{
    const double denom = myBuilder->pieceCount ? myBuilder->pieceCount : 1;
    myProgressBar->setValue( (int) ((100.0 * myBuilder->pieceIndex) / denom ) );

    refresh( );

    if( myBuilder->isDone )
        setIsBuilding( false );

    //tr_metainfo_builder_err    result;
}

void
MakeDialog :: makeTorrent( )
{
    if( !myBuilder )
        return;

    int tier = 0;
    QList<tr_tracker_info> trackers;
    foreach( QString line, myTrackerEdit->toPlainText().split("\n") ) {
        line = line.trimmed( );
        if( line.isEmpty( ) )
            ++tier;
        else {
            tr_tracker_info tmp;
            tmp.announce = tr_strdup( line.toUtf8().constData( ) );
            tmp.tier = tier;
            std::cerr << "tier [" << tmp.tier << "] announce [" << tmp.announce << ']' << std::endl;
            trackers.append( tmp );
        }
    }

    tr_makeMetaInfo( myBuilder,
                     NULL,
                     &trackers.front(),
                     trackers.size(),
                     myCommentEdit->text().toUtf8().constData(),
                     myPrivateCheck->isChecked() );
    
    refresh( );
    setIsBuilding( true );
}

void
MakeDialog :: onButtonBoxClicked( QAbstractButton * button )
{
    if( button == myMakeButton )
        makeTorrent( );

    if( button == myStopButton )
        myBuilder->abortFlag = true;

    if( button == myCloseButton )
        deleteLater( );
}

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

void
MakeDialog :: onSourceChanged( )
{
    if( myBuilder ) {
        tr_metaInfoBuilderFree( myBuilder );
        myBuilder = 0;
    }

    const QString filename = mySourceEdit->text( );
    if( !filename.isEmpty( ) )
        myBuilder = tr_metaInfoBuilderCreate( filename.toUtf8().constData() );

    QString text;
    if( !myBuilder )
        text = tr( "<i>No source selected<i>" );
    else {
        QString files = tr( "%Ln File(s)", 0, myBuilder->fileCount );
        QString pieces = tr( "%Ln Piece(s)", 0, myBuilder->pieceCount );
        text = tr( "%1 in %2; %3 @ %4" )
                 .arg( Utils::sizeToString( myBuilder->totalSize ) )
                 .arg( files )
                 .arg( pieces )
                 .arg( Utils::sizeToString( myBuilder->pieceSize ) );
    }
    mySourceLabel->setText( text );

    refresh( );
}

void
MakeDialog :: onFileSelectedInDialog( const QString& path )
{
    mySourceEdit->setText( path );
    onSourceChanged( );
}

void
MakeDialog :: onFolderButtonPressed( )
{
    QFileDialog * f = new QFileDialog( this );
    f->setFileMode( QFileDialog :: Directory );
    connect( f, SIGNAL(fileSelected(const QString&)), this, SLOT(onFileSelectedInDialog(const QString&)));
    f->show( );
}

void
MakeDialog :: onFileButtonPressed( )
{
    QFileDialog * f = new QFileDialog( this );
    f->setFileMode( QFileDialog :: ExistingFile );
    connect( f, SIGNAL(fileSelected(const QString&)), this, SLOT(onFileSelectedInDialog(const QString&)));
    f->show( );
}
