// -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4; -*-
/* This file is part of the KDE project
   Copyright 2004 Brad Hards <bradh@frogmouth.net>
   Loosely based on webpresention.cc, which is:
     Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
     Copyright 2001, 2002 Nicolas GOUTTE <goutte@kde.org>
     Copyright 2002 Ariya Hidayat <ariya@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include "KPrMSPresentationSetup.h"

#include "KPrView.h"
#include "KPrDocument.h"

#include "KPrCanvas.h"
#include "KPrPage.h"

#include <tdeio/netaccess.h>
#include <tdetempfile.h>

#include <tqdir.h>
#include <tqframe.h>
#include <tqfileinfo.h>
#include <tqhbox.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqpixmap.h>
#include <tqpainter.h>
#include <tqpushbutton.h>
#include <tqvbox.h>
#include <tqwhatsthis.h>

#include <tdeapplication.h>
#include <kbuttonbox.h>
#include <kcolorbutton.h>
#include <tdeglobal.h>
#include <tdeglobalsettings.h>
#include <klineedit.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kprogress.h>
#include <kstandarddirs.h>
#include <kurlrequester.h>
#include <kstdguiitem.h>
#include <kpushbutton.h>

KPrMSPresentation::KPrMSPresentation( KPrDocument *_doc, KPrView *_view )
{
    doc = _doc;
    view = _view;
    init();
}

KPrMSPresentation::KPrMSPresentation( const KPrMSPresentation &msPres )
    : title( msPres.title ),
      slideInfos( msPres.slideInfos ), backColour( msPres.backColour ),
      textColour( msPres.textColour ), path( msPres.path )
{
    doc = msPres.doc;
    view = msPres.view;
}

void KPrMSPresentation::initCreation( KProgress *progressBar )
{
    int p;

    // the title images, and the subsequent real images need to
    // be in a file under DCIM/, and they start at 101MSPJP, so
    // we create the DCIM file, and then iterate through looking
    // for the next "available" directory slot
    KURL str(  path + "/DCIM"  );
    TDEIO::NetAccess::mkdir( str,( TQWidget* )0L  );

    p = progressBar->progress();
    progressBar->setProgress( ++p );
    kapp->processEvents();

    for (int dirNum = 101; dirNum < 999; dirNum++) {
        slidePath = TQString("/DCIM/%1MSPJP").arg(dirNum);
        if (! TDEIO::NetAccess::exists(( path + slidePath), true, ( TQWidget* )0L) )
            break;
    }

    p = progressBar->progress();
    progressBar->setProgress( ++p );
    kapp->processEvents();

    str = (  path + slidePath );
    TDEIO::NetAccess::mkdir( str,( TQWidget* )0L  );
    p = progressBar->progress();
    progressBar->setProgress( ++p );
    kapp->processEvents();

    // now do the SPP file directory
    str = (  path + "/MSSONY" );
    TDEIO::NetAccess::mkdir( str,( TQWidget* )0L  );

    p = progressBar->progress();
    progressBar->setProgress( ++p );
    kapp->processEvents();
    str = (  path + "/MSSONY/PJ" );
    TDEIO::NetAccess::mkdir( str,( TQWidget* )0L  );


    p = progressBar->progress();
    progressBar->setProgress( ++p );
    kapp->processEvents();

    // create the title slides
    TQPixmap titleSlide( 1024, 768 );
    titleSlide.fill( backColour );
    TQPainter painter( &titleSlide );

    //the second title is just blank, so create that now
    KTempFile tmp;
    TQString filename = path + slidePath + "/SPJT0002.JPG";
    titleSlide.save( tmp.name(), "JPEG" );
    TDEIO::NetAccess::file_move( tmp.name(), filename, -1, true /*overwrite*/);

    p = progressBar->progress();
    progressBar->setProgress( ++p );
    kapp->processEvents();

    // and put the specified title string on the first slide
    TQFont textFont( "SansSerif", 96 );
    painter.setFont( textFont );
    painter.setPen( textColour );
    painter.drawText( titleSlide.rect(), TQt::AlignCenter | TQt::WordBreak, title );
    filename = path + slidePath + "/SPJT0001.JPG";

    KTempFile tmp2;
    titleSlide.save( tmp2.name(), "JPEG" );
    TDEIO::NetAccess::file_move( tmp2.name(), filename, -1, true /*overwrite*/);

    p = progressBar->progress();
    progressBar->setProgress( ++p );
    kapp->processEvents();

}

void KPrMSPresentation::createSlidesPictures( KProgress *progressBar )
{
    if ( slideInfos.isEmpty() )
        return;
    TQString filename;
    int p;
    for ( unsigned int i = 0; i < slideInfos.count(); i++ ) {
        int pgNum = slideInfos[i].pageNumber;
        filename.sprintf("/SPJP%04i.JPG", i+3);

        KTempFile tmp;

        view->getCanvas()->exportPage( pgNum, 1023, 767,
                                       tmp.name(), "JPEG" );

        TDEIO::NetAccess::file_move( tmp.name(), ( path + slidePath + filename ), -1, true /*overwrite*/);

        p = progressBar->progress();
        progressBar->setProgress( ++p );
        kapp->processEvents();
    }
}

void KPrMSPresentation::createIndexFile( KProgress *progressBar )
{
    int p;
    KTempFile sppFile;

    TQString filenameStore = (path + "/MSSONY/PJ/" + title + ".SPP");

    TQDataStream sppStream( sppFile.file() );
    sppStream.setByteOrder(TQDataStream::LittleEndian);
    p = progressBar->progress();
    progressBar->setProgress( ++p );
    kapp->processEvents();

    // We are doing little endian
    sppStream << (TQ_UINT32)0x00505053; // SPP magic header
    sppStream << (TQ_UINT32)0x00000000; // four null bytes
    sppStream << (TQ_UINT32)0x30303130; // version(?) 0100
    sppStream << (TQ_UINT32)0x00000000; // more nulls
    sppStream << (TQ_UINT32)(slideInfos.count());

    // DCIM path 1, 68 bytes null padded
    char buff[68];
    strncpy( buff, TQString("%1").arg(slidePath).ascii(), 67 );
    buff[67] = 0x00;
    sppStream.writeRawBytes( buff, 68 );
    sppStream << (TQ_UINT32)0x00000001; // fixed value
    sppStream << (TQ_UINT32)0x00000005; // fixed value
    sppStream << (TQ_UINT32)0x00000000; // more nulls
    sppStream << (TQ_UINT32)0x00000000; // more nulls
    sppStream << (TQ_UINT32)0x00000000; // more nulls
    sppStream << (TQ_UINT32)0x00000000; // more nulls
    sppStream << (TQ_UINT32)0x00000000; // more nulls
    sppStream << (TQ_UINT32)0x00000000; // more nulls
    p = progressBar->progress();
    progressBar->setProgress( ++p );
    kapp->processEvents();

    // title 1, 16 bytes null padded
    strncpy( buff, "SPJT0001.JPG", 15 );
    buff[15] = 0x00;
    sppStream.writeRawBytes( buff, 16 );

    // title 2, 16 bytes null padded
    strncpy( buff, "SPJT0002.JPG", 15 );
    buff[15] = 0x00;
    sppStream.writeRawBytes( buff, 16 );


    // type face (?), 44 bytes null padded
    strncpy( buff, "MS Sans Serif", 43 );
    buff[44] = 0x00;
    sppStream.writeRawBytes( buff, 44 );

    //not really sure what this is about
    sppStream << (TQ_UINT32)0xffff0000;
    sppStream << (TQ_UINT32)0xffff00ff;
    sppStream << (TQ_UINT32)0xffff00ff;
    sppStream << (TQ_UINT32)0x000000ff;
    sppStream << (TQ_UINT32)0x00000002;
    for (int i = 0; i < (296/4); i++) {
        sppStream << (TQ_UINT32)0x00000000;
    }
    p = progressBar->progress();
    progressBar->setProgress( ++p );
    kapp->processEvents();

    // Add in the slide filenames
    TQString filename;
    for ( unsigned int i = 0; i < slideInfos.count(); i++ ) {
        filename.sprintf("SPJP%04i.JPG", i+3);
        strncpy( buff, filename.ascii(), 63 );
        buff[64] = 0x00;
        sppStream.writeRawBytes( buff, 64 );
        p = progressBar->progress();
        progressBar->setProgress( ++p );
        kapp->processEvents();
    }

    // OK, now we need to fill to 16384 bytes
    // the logic is 16384 bytes total, lead in is 512 bytes, and there
    // is 64 bytes for each real slide
    for(unsigned int i = 0;  i < (16384-512-64*(slideInfos.count()))/4; i++) {
        sppStream << (TQ_UINT32)0x00000000;
    }

    p = progressBar->progress();
    progressBar->setProgress( ++p );
    kapp->processEvents();

    sppFile.close();
    TDEIO::NetAccess::file_move( sppFile.name(), filenameStore, -1, true /*overwrite*/);
}

void KPrMSPresentation::init()
{
    title = i18n("Slideshow");

    for ( unsigned int i = 0; i < doc->getPageNums(); i++ )
    {
        if ( doc->isSlideSelected( i ) )
        {
            SlideInfo info;
            info.pageNumber = i;
            slideInfos.append( info );
        }
    }
    if ( slideInfos.isEmpty() )
        kdWarning() << "No slides selected!" << endl;
    backColour = TQt::black;
    textColour = TQt::white;

    path = TDEGlobalSettings::documentPath();
}

KPrMSPresentationSetup::KPrMSPresentationSetup( KPrDocument *_doc, KPrView *_view )
    : TQDialog( 0, "", false ), msPres(  _doc, _view )
{
    doc = _doc;
    view = _view;


    TQLabel *helptext = new TQLabel( this );
    helptext->setAlignment( TQt::WordBreak | TQt::AlignTop| TQt::AlignLeft );
    helptext->setText( i18n( "Please enter the directory where the memory stick "
                             "presentation should be saved. Please also enter a "
                             "title for the slideshow presentation. " ) );

    TQLabel *lable2 = new TQLabel( i18n("Path:"), this );
    lable2->setAlignment( TQt::AlignVCenter | TQt::AlignRight );
    path=new KURLRequester( this );
    path->setMode( KFile::Directory);
    path->lineEdit()->setText(msPres.getPath());
    lable2->setBuddy(path);
    TQHBoxLayout *pathLayout = new TQHBoxLayout;
    pathLayout->addWidget(lable2);
    pathLayout->addWidget(path);

    connect( path, TQT_SIGNAL( textChanged(const TQString&) ),
             this, TQT_SLOT( slotChoosePath(const TQString&) ) );
    connect( path, TQT_SIGNAL( urlSelected( const TQString&) ),
             this, TQT_SLOT( slotChoosePath(const TQString&) ) );


    TQLabel *lable1 = new TQLabel( i18n("Title:"), this, "lable1" );
    lable1->setAlignment( TQt::AlignVCenter | TQt::AlignRight );
    // TODO - check if there is already a presentation with this title, and
    // add a number after it until there isn't.
    title = new KLineEdit( msPres.getTitle(), this );
    lable1->setBuddy( title );
    TQHBoxLayout *titleLayout = new TQHBoxLayout;
    titleLayout->addWidget( lable1 );
    titleLayout->addWidget( title );

    TQHBox *moreBox = new TQHBox( this );
    TQPushButton *showColourButton = new TQPushButton( i18n("&Set Colors"), moreBox );
    showColourButton->setToggleButton( true );
    connect( showColourButton, TQT_SIGNAL( toggled(bool) ), this, TQT_SLOT( showColourGroup(bool) ) );

    TQVBoxLayout *topLayout = new TQVBoxLayout;
    topLayout->addWidget( helptext );
    topLayout->addSpacing( 10 );
    topLayout->addLayout( pathLayout );
    topLayout->addLayout( titleLayout );
    topLayout->addWidget( moreBox );

    colourGroup = new TQGroupBox( 2, Qt::Vertical,
                                            i18n("Preliminary Slides"),
                                            this , "colourBox" );
    TQWhatsThis::add( colourGroup,
                     i18n( "This section allows you to set the colors for "
                           "the preliminary slides; it does not affect the "
                           "presentation in any way, and it is normal to "
                           "leave these set to the default.") );
    TQHBox *textColourLayout = new TQHBox( colourGroup );
    TQLabel *lable3 = new TQLabel( i18n("Text color:"), textColourLayout );
    lable3->setAlignment( TQt::AlignVCenter | TQt::AlignRight );
    textColour = new KColorButton( msPres.getTextColour(), textColourLayout );
    lable3->setBuddy( textColour );

    TQHBox *backgroundColourLayout = new TQHBox( colourGroup );
    TQLabel *lable4 = new TQLabel( i18n("Background color:"), backgroundColourLayout );
    lable4->setAlignment( TQt::AlignVCenter | TQt::AlignRight );
    backColour = new KColorButton( msPres.getBackColour(), backgroundColourLayout );
    lable4->setBuddy( backColour );
    colourGroup->setHidden( true );

    TQHBox *buttonLayout = new TQHBox( this );
    KPushButton *helpButton = new KPushButton( KStdGuiItem::help(), buttonLayout );
    TQWhatsThis::add( helpButton,
                     i18n( "Selecting this button will take you to the KPresenter "
                           "documentation that provides more information on how "
                           "to use the Memory Stick export function. ") );
    KPushButton *createButton = new KPushButton( KStdGuiItem::ok(), buttonLayout );
    TQWhatsThis::add( createButton,
                     i18n( "Selecting this button will proceed to generating "
                           "the presentation in the special Sony format." ) );
    KPushButton *cancelButton = new KPushButton( KStdGuiItem::cancel(), buttonLayout );
    TQWhatsThis::add( cancelButton,
                     i18n( "Selecting this button will cancel out of the "
                           "generation of the presentation, and return "
                           "to the normal KPresenter view. No files will "
                           "be affected." ) );

    mainLayout = new TQVBoxLayout( this );
    mainLayout->setMargin(11);
    mainLayout->setSpacing(6);
    mainLayout->addLayout(topLayout);
    mainLayout->addSpacing( 10 );
    mainLayout->addWidget(colourGroup);
    mainLayout->addWidget(buttonLayout);
    mainLayout->setResizeMode( TQLayout::Fixed );
    mainLayout->setGeometry( TQRect( 0, 0, 300, 220 ) );

    connect( helpButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT ( helpMe() ) );
    connect( cancelButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( reject() ) );
    connect( createButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( finish() ) );
}

KPrMSPresentationSetup::~KPrMSPresentationSetup()
{
    view->enableMSPres();
}

void KPrMSPresentationSetup::createMSPresentation( KPrDocument *_doc, KPrView *_view )
{
    KPrMSPresentationSetup *dlg = new KPrMSPresentationSetup( _doc, _view );

    dlg->setCaption( i18n( "Create Memory Stick Slideshow" ) );
    dlg->exec();
    delete dlg;
}

void KPrMSPresentationSetup::showColourGroup(bool on)
{
    if (on) {
        colourGroup->setHidden( false );
        mainLayout->setGeometry( TQRect(0, 0, 300, 220 ) );
    } else {
        colourGroup->setHidden( true );
        mainLayout->setGeometry( TQRect(0, 0, 300, 320 ) );
    }
}

void KPrMSPresentationSetup::helpMe()
{
    kapp->invokeHelp("ms-export");
}

void KPrMSPresentationSetup::finish()
{
    msPres.setTitle( title->text() );

    msPres.setBackColour( backColour->color() );
    msPres.setTextColour( textColour->color() );
    msPres.setPath( path->lineEdit()->text() );

    // Things to sanity check:
    // 1. that the directory exists. If not, offer to create it.
    // 2. that the directory is writable.
    // 3. that the .spp file doesn't already exist. If it does, offer to overwrite it.
    // If we fail to create a directory, or the user tells us not to bother creating it,
    // or the user doesn't want to overwrite it, go back.
    TQString pathname = path->lineEdit()->text();

    // path doesn't exist. ask user if it should be created.
    if ( !TDEIO::NetAccess::exists(pathname, false, this) ) {
        TQString msg = i18n( "<qt>The directory <b>%1</b> does not exist.<br>"
                            "Do you want create it?</qt>" );
        if( KMessageBox::questionYesNo( this, msg.arg( pathname ),
                                        i18n( "Directory Not Found" ) )
            == KMessageBox::Yes)
            {
                // we are trying to create the directory
                TQDir dir;
                bool ok = TDEIO::NetAccess::mkdir( pathname,this );
                if( !ok ) {
                    // then directory couldn't be created
                    KMessageBox::sorry( this,
                                        i18n( "Cannot create directory." ) );
                    path->setFocus();
                    return;
                }
            }
        else {
            // user preferred not to create directory
            path->setFocus();
            return;
        }
    }

    TQString sppFile( pathname + "/MSSONY/PJ/" + title->text() + ".SPP" );
    if (TDEIO::NetAccess::exists(sppFile, false, this ) ) {
        if ( KMessageBox::warningYesNo( 0,
                                   i18n( "You are about to overwrite an existing index "
                                         "file : %1.\n "
                                         "Do you want to proceed?" ).arg( sppFile ),
                                   i18n( "Overwrite Presentation" ) )
             == KMessageBox::No) {
            path->setFocus();
            return;
        }
    }

    close();

    KPrMSPresentationCreateDialog::createMSPresentation( doc, view, msPres );

}

void KPrMSPresentationSetup::slotChoosePath(const TQString &text)
{
    msPres.setPath(text);
}




KPrMSPresentationCreateDialog::KPrMSPresentationCreateDialog( KPrDocument *_doc, KPrView *_view,
                                                            const KPrMSPresentation &_msPres )
    : TQDialog( 0, "", false ), msPres( _msPres )
{
    doc = _doc;
    view = _view;

    setupGUI();
}

KPrMSPresentationCreateDialog::~KPrMSPresentationCreateDialog()
{
    view->enableMSPres();
}

void KPrMSPresentationCreateDialog::createMSPresentation( KPrDocument *_doc, KPrView *_view,
                                                         const KPrMSPresentation &_msPres )
{
    KPrMSPresentationCreateDialog *dlg = new KPrMSPresentationCreateDialog( _doc, _view, _msPres );

    dlg->setCaption( i18n( "Create Memory Stick Slideshow" ) );
    dlg->resize( 400, 250 );
    dlg->show();
    dlg->start();
}

void KPrMSPresentationCreateDialog::start()
{
    setCursor( waitCursor );
    initCreation();
    createSlidesPictures();
    createIndexFile();
    setCursor( arrowCursor );

    bDone->setEnabled( true );
}

void KPrMSPresentationCreateDialog::initCreation()
{
    TQFont f = step1->font(), f2 = step1->font();
    f.setBold( true );
    step1->setFont( f );

    progressBar->setProgress( 0 );
    progressBar->setTotalSteps( msPres.initSteps() );

    msPres.initCreation( progressBar );

    step1->setFont( f2 );
    progressBar->setProgress( progressBar->totalSteps() );
}

void KPrMSPresentationCreateDialog::createSlidesPictures()
{
    TQFont f = step2->font(), f2 = f;
    f.setBold( true );
    step2->setFont( f );

    progressBar->setProgress( 0 );
    if ( msPres.slidesSteps() > 0 )
    {
        progressBar->setTotalSteps( msPres.slidesSteps() );
        msPres.createSlidesPictures( progressBar );
    }

    step2->setFont( f2 );
    progressBar->setProgress( progressBar->totalSteps() );
}

void KPrMSPresentationCreateDialog::createIndexFile()
{
    TQFont f = step3->font(), f2 = f;
    f.setBold( true );
    step3->setFont( f );

    progressBar->setProgress( 0 );
    if ( msPres.indexFileSteps() > 0 )
    {
        progressBar->setTotalSteps( msPres.indexFileSteps() );
        msPres.createIndexFile( progressBar );
    }

    step3->setFont( f2 );
    progressBar->setProgress( progressBar->totalSteps() );
}

void KPrMSPresentationCreateDialog::setupGUI()
{
    back = new TQVBox( this );
    back->setMargin( KDialog::marginHint() );

    TQFrame *line;

    step1 = new TQLabel( i18n( "Create directory structure" ), back );
    step2 = new TQLabel( i18n( "Create pictures of the slides" ), back );
    step3 = new TQLabel( i18n( "Create index file" ), back );

    line = new TQFrame( back );
    line->setFrameStyle( TQFrame::HLine | TQFrame::Sunken );
    line->setMaximumHeight( 20 );

    progressBar = new KProgress( back );

    line = new TQFrame( back );
    line->setFrameStyle( TQFrame::HLine | TQFrame::Sunken );
    line->setMaximumHeight( 20 );

    KButtonBox *bb = new KButtonBox( back );
    bb->addStretch();
    bDone = bb->addButton( i18n( "Done" ) );

    bDone->setEnabled( false );

    connect( bDone, TQT_SIGNAL( clicked() ), this, TQT_SLOT( accept() ) );
}

void KPrMSPresentationCreateDialog::resizeEvent( TQResizeEvent *e )
{
    TQDialog::resizeEvent( e );
    back->resize( size() );
}

#include "KPrGradient.h"
#include "KPrMSPresentationSetup.moc"
