/*
  receive a file on DCC protocol
  begin:     Mit Aug 7 2002
  copyright: (C) 2002 by Dario Abatianni
  email:     eisfuchs@tigress.com
*/
// Copyright (C) 2004-2007 Shintaro Matsuoka <shin@shoegazed.org>
// Copyright (C) 2004,2005 John Tapsell <john@geola.co.uk>

/*
  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.
*/

#ifndef DCCTRANSFERRECV_H
#define DCCTRANSFERRECV_H

#include "dcctransfer.h"
// TODO: remove the dependence
#include "dccresumedialog.h"

#include <tqptrlist.h>


class TQFile;
class TQTimer;

namespace TDEIO
{
    class Job;
    class TransferJob;
}

namespace KNetwork
{
    class TDEServerSocket;
    class KStreamSocket;
}

class DccTransferRecvWriteCacheHandler;

class DccTransferRecv : public DccTransfer
{
    TQ_OBJECT
  

    public:
        DccTransferRecv(TQObject* parent);
        virtual ~DccTransferRecv();

        // REQUIRED
        void setPartnerIp( const TQString& ip );
        // REQUIRED
        void setPartnerPort( const TQString& port );
        // REQUIRED
        void setFileSize( unsigned long fileSize );
        // OPTIONAL, if not specified, "unnamed_file"
        // TODO: "$sendername-$receiveddate" is better
        void setFileName( const TQString& fileName );
        // OPTIONAL, if not specified, default folder + the file name
        void setFileURL( const KURL& url );
        // OPTIONAL
        void setReverse( bool reverse, const TQString& reverseToken );

    public slots:
        virtual bool queue();

        /** The user has accepted the download.
         *  Check we are saving it somewhere valid, create any directories needed, and
         *  connect to remote host.
         */
        virtual void start();
        /** The user has chosen to abort.
         *  Either by chosen to abort directly, or by choosing cancel when
         *  prompted for information on where to save etc.
         *  Not called when it fails due to another problem.
         */
        virtual void abort();
        void startResume( unsigned long position );

    protected slots:
        // Local TDEIO
        void slotLocalCanResume( TDEIO::Job* job, TDEIO::filesize_t size );
        void slotLocalGotResult( TDEIO::Job* job );
        void slotLocalReady( TDEIO::Job* job );
        void slotLocalWriteDone();
        void slotLocalGotWriteError( const TQString& errorString );

        // Remote DCC
        void connectWithSender();
        void startReceiving();
        void connectionFailed( int errorCode );
        void readData();
        void sendAck();
        void connectionTimeout();
        void slotSocketClosed();

        // Reverse DCC
        void slotServerSocketReadyAccept();
        void slotServerSocketGotError( int errorCode );

    protected:
        void cleanUp();
        void failed(const TQString& errorMessage = TQString() );

                                                  // (startPosition == 0) means "don't resume"
        void prepareLocalKio( bool overwrite, bool resume, TDEIO::fileoffset_t startPosition = 0 );
        void askAndPrepareLocalKio( const TQString& message, int enabledActions, DccResumeDialog::ReceiveAction defaultAction, TDEIO::fileoffset_t startPosition = 0 );

        /**
         * This calls TDEIO::NetAccess::mkdir on all the subdirectories of dirURL, to
         * create the given directory.  Note that a url like  file:/foo/bar  will
         * make sure both foo and bar are created.  It assumes everything in the path is
         * a directory.
         * Note: If the directory already exists, returns true.
         *
         * @param dirURL A url for the directory to create.
         * @return True if the directory now exists.  False if there was a problem and the directory doesn't exist.
         */
        bool createDirs(const KURL &dirURL) const;

        void requestResume();
        // for non-reverse DCC
        void connectToSendServer();
        // for reverse DCC
        bool startListeningForSender();

        void startConnectionTimer( int sec );
        void stopConnectionTimer();

    protected:
        KURL m_saveToTmpFileURL;
        ///Current filesize of the file saved on the disk.
        TDEIO::filesize_t m_saveToFileSize;
        ///Current filesize of the file+".part" saved on the disk.
        TDEIO::filesize_t m_partialFileSize;
        DccTransferRecvWriteCacheHandler* m_writeCacheHandler;
        bool m_saveToFileExists;
        bool m_partialFileExists;
        TQTimer* m_connectionTimer;

        KNetwork::TDEServerSocket* m_serverSocket;
        KNetwork::KStreamSocket* m_recvSocket;

    private:
        virtual TQString getTypeText() const;
        virtual TQPixmap getTypeIcon() const;
};

class DccTransferRecvWriteCacheHandler : public TQObject
{
    TQ_OBJECT
  

        public:
        explicit DccTransferRecvWriteCacheHandler( TDEIO::TransferJob* transferJob );
        virtual ~DccTransferRecvWriteCacheHandler();

        void append( char* data, int size );
        bool write( bool force );
        void close();
        void closeNow();

        signals:
        void dataFinished();                      // ->  m_transferJob->slotFinished()
        void done();                              // ->  DccTransferRecv::writeDone()
                                                  // ->  DccTransferRecv::slotWriteError()
        void gotError( const TQString& errorString );

    protected slots:
                                                  // <-  m_transferJob->dataReq()
        void slotKIODataReq( TDEIO::Job* job, TQByteArray& data );
        void slotKIOResult( TDEIO::Job* job );      // <-  m_transferJob->result()

    protected:
        TDEIO::TransferJob* m_transferJob;
        bool m_writeAsyncMode;
        bool m_writeReady;

        TQValueList<TQByteArray> m_cacheList;
        TQDataStream* m_cacheStream;
};

#endif  // DCCTRANSFERRECV_H
