/***************************************************************************
 *   Copyright (C) 2003-2007 by Joachim Eibl                               *
 *   joachim.eibl at gmx.de                                                   *
 *                                                                         *
 *   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 FILEACCESS_H
#define FILEACCESS_H

#include <tqdialog.h>
#include <tqfileinfo.h>
#include <kprogress.h>
#include <tdeio/job.h>
#include <tdeio/jobclasses.h>
#include <kurldrag.h>
#include <list>
#include <tqstring.h>
#include <tqdatetime.h>

bool wildcardMultiMatch( const TQString& wildcard, const TQString& testString, bool bCaseSensitive );

class t_DirectoryList;

class FileAccess
{
public:
   FileAccess();
   ~FileAccess();
   FileAccess( const TQString& name, bool bWantToWrite=false ); // name: local file or dirname or url (when supported)
   void setFile( const TQString& name, bool bWantToWrite=false );

   bool isValid() const;
   bool isFile() const;
   bool isDir() const;
   bool isSymLink() const;
   bool exists() const;
   long size() const;            // Size as returned by stat().
   long sizeForReading();  // If the size can't be determined by stat() then the file is copied to a local temp file.
   bool isReadable() const;
   bool isWritable() const;
   bool isExecutable() const;
   bool isHidden() const;
   TQString readLink() const;

   TQDateTime   created()       const;
   TQDateTime   lastModified()  const;
   TQDateTime   lastRead()      const;

   TQString fileName() const; // Just the name-part of the path, without parent directories
   TQString filePath() const; // The path-string that was used during construction
   TQString prettyAbsPath() const;
   KURL url() const;
   TQString absFilePath() const;

   bool isLocal() const;

   bool readFile(void* pDestBuffer, unsigned long maxLength );
   bool writeFile(const void* pSrcBuffer, unsigned long length );
   bool listDir( t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden,
                 const TQString& filePattern, const TQString& fileAntiPattern,
                 const TQString& dirAntiPattern, bool bFollowDirLinks, bool bUseCvsIgnore );
   bool copyFile( const TQString& destUrl );
   bool createBackup( const TQString& bakExtension );

   static TQString tempFileName();
   static bool removeTempFile( const TQString& );
   bool removeFile();
   static bool removeFile( const TQString& );
   static bool makeDir( const TQString& );
   static bool removeDir( const TQString& );
   static bool exists( const TQString& );
   static TQString cleanDirPath( const TQString& );

   //bool chmod( const TQString& );
   bool rename( const TQString& );
   static bool symLink( const TQString& linkTarget, const TQString& linkLocation );

   void addPath( const TQString& txt );
   TQString getStatusText();
private:
   void setUdsEntry( const TDEIO::UDSEntry& e );
   KURL m_url;
   bool m_bLocal;
   bool m_bValidData;

   unsigned long m_size;
   TQDateTime m_modificationTime;
   TQDateTime m_accessTime;
   TQDateTime m_creationTime;
   bool m_bReadable;
   bool m_bWritable;
   bool m_bExecutable;
   bool m_bExists;
   bool m_bFile;
   bool m_bDir;
   bool m_bSymLink;
   bool m_bHidden;
   long m_fileType; // for testing only

   TQString m_linkTarget;
   TQString m_user;
   TQString m_group;
   TQString m_name;
   TQString m_path;
   TQString m_absFilePath;
   TQString m_localCopy;
   TQString m_statusText;  // Might contain an error string, when the last operation didn't succeed.

   friend class FileAccessJobHandler;
};

class t_DirectoryList : public std::list<FileAccess>
{};


class FileAccessJobHandler : public TQObject
{
   Q_OBJECT
  
public:
   FileAccessJobHandler( FileAccess* pFileAccess );

   bool get( void* pDestBuffer, long maxLength );
   bool put( const void* pSrcBuffer, long maxLength, bool bOverwrite, bool bResume=false, int permissions=-1 );
   bool stat(int detailLevel=2, bool bWantToWrite=false );
   bool copyFile( const TQString& dest );
   bool rename( const TQString& dest );
   bool listDir( t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden,
                 const TQString& filePattern, const TQString& fileAntiPattern,
                 const TQString& dirAntiPattern, bool bFollowDirLinks, bool bUseCvsIgnore );
   bool mkDir( const TQString& dirName );
   bool rmDir( const TQString& dirName );
   bool removeFile( const TQString& dirName );
   bool symLink( const TQString& linkTarget, const TQString& linkLocation );

private:
   FileAccess* m_pFileAccess;
   bool m_bSuccess;

   // Data needed during Job
   long m_transferredBytes;
   char* m_pTransferBuffer;  // Needed during get or put
   long m_maxLength;

   TQString m_filePattern;
   TQString m_fileAntiPattern;
   TQString m_dirAntiPattern;
   t_DirectoryList* m_pDirList;
   bool m_bFindHidden;
   bool m_bRecursive;
   bool m_bFollowDirLinks;

   bool scanLocalDirectory( const TQString& dirName, t_DirectoryList* dirList );

private slots:
   void slotStatResult( TDEIO::Job* );
   void slotSimpleJobResult( TDEIO::Job* pJob );
   void slotPutJobResult( TDEIO::Job* pJob );

   void slotGetData(TDEIO::Job*,const TQByteArray&);
   void slotPutData(TDEIO::Job*, TQByteArray&);

   void slotListDirInfoMessage( TDEIO::Job*, const TQString& msg );
   void slotListDirProcessNewEntries( TDEIO::Job *, const TDEIO::UDSEntryList& l );

   void slotPercent( TDEIO::Job* pJob, unsigned long percent );
};

class ProgressDialog : public TQDialog
{
   Q_OBJECT
  
public:
   ProgressDialog( TQWidget* pParent );

   void setStayHidden( bool bStayHidden );
   void setInformation( const TQString& info, bool bRedrawUpdate=true );
   void setInformation( const TQString& info, double dCurrent, bool bRedrawUpdate=true );
   void setCurrent( double dCurrent, bool bRedrawUpdate=true  );
   void step( bool bRedrawUpdate=true );
   void setMaxNofSteps( int dMaxNofSteps );
   void push();
   void pop(bool bRedrawUpdate=true);

   // The progressbar goes from 0 to 1 usually.
   // By supplying a subrange transformation the subCurrent-values
   // 0 to 1 will be transformed to dMin to dMax instead.
   // Requirement: 0 < dMin < dMax < 1
   void setRangeTransformation( double dMin, double dMax );
   void setSubRangeTransformation( double dMin, double dMax );

   void exitEventLoop();
   void enterEventLoop( TDEIO::Job* pJob, const TQString& jobInfo );

   bool wasCancelled();
   void show();
   void hide();
   
   virtual void timerEvent(TQTimerEvent*);
private:

   struct ProgressLevelData
   {
      ProgressLevelData()
      {
         m_dCurrent=0; m_maxNofSteps=1; m_dRangeMin=0; m_dRangeMax=1; 
         m_dSubRangeMin = 0; m_dSubRangeMax = 1;
      }
      double m_dCurrent;
      int    m_maxNofSteps;     // when step() is used.
      double m_dRangeMax;
      double m_dRangeMin;
      double m_dSubRangeMax;
      double m_dSubRangeMin;
   };
   std::list<ProgressLevelData> m_progressStack;
   
   int m_progressDelayTimer;

   KProgress* m_pProgressBar;
   KProgress* m_pSubProgressBar;
   TQLabel* m_pInformation;
   TQLabel* m_pSubInformation;
   TQLabel* m_pSlowJobInfo;
   TQPushButton* m_pAbortButton;
   void recalc(bool bRedrawUpdate);
   TQTime m_t1;
   TQTime m_t2;
   bool m_bWasCancelled;
   TDEIO::Job* m_pJob;
   TQString m_currentJobInfo;  // Needed if the job doesn't stop after a reasonable time.
   bool m_bStayHidden;
protected:
   virtual void reject();
private slots:
   void delayedHide();
   void slotAbort();
};

// When using the ProgressProxy you need not take care of the push and pop, except when explicit.
class ProgressProxy
{
public:
   ProgressProxy();
   ~ProgressProxy();
   
   void setInformation( const TQString& info, bool bRedrawUpdate=true );
   void setInformation( const TQString& info, double dCurrent, bool bRedrawUpdate=true );
   void setCurrent( double dCurrent, bool bRedrawUpdate=true  );
   void step( bool bRedrawUpdate=true );
   void setMaxNofSteps( int dMaxNofSteps );
   bool wasCancelled();
   void setRangeTransformation( double dMin, double dMax );
   void setSubRangeTransformation( double dMin, double dMax );
private:
};

extern ProgressDialog* g_pProgressDialog;



#endif

