/* -*- mode: C++; c-file-style: "gnu" -*-
    This file is part of KMail, the KDE mail client.
    Copyright (c) 2000 Don Sanders <sanders@kde.org>

    KMail 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.

    KMail 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
// Virtual base class for mail folder with .*.index style index

#ifndef kmfolderindex_h
#define kmfolderindex_h

#include "folderstorage.h"
#include "kmmsglist.h"

/**
 * @short A FolderStorage with an index for faster access to often used
 * message properties..
 *
 * This class represents a message store which has an index for providing fast
 * access to often used message properties, namely those displayed in the list
 * of messages (KMHeaders).
 * 
 * @author Don Sanders <sanders@kde.org>
 */

class KMFolderIndex: public FolderStorage
{
  Q_OBJECT
  
  //TODO:Have to get rid of this friend declaration and add necessary pure
  //virtuals to kmfolder.h so that KMMsgBase::parent() can be a plain KMFolder
  //rather than a KMFolderIndex. Need this for database indices.
  friend class ::KMMsgBase;
public:

  /** This enum indicates the status of the index file. It's returned by
      indexStatus().
   */
  enum IndexStatus { IndexOk,
                     IndexMissing,
                     IndexCorrupt,
                     IndexTooOld
  };

  /** Usually a parent is given. But in some cases there is no
    fitting parent object available. Then the name of the folder
    is used as the absolute path to the folder file. */
  KMFolderIndex(KMFolder* folder, const char* name=0);
  virtual ~KMFolderIndex();
  virtual int count(bool cache = false) const;

  virtual KMMsgBase* takeIndexEntry( int idx ) { return mMsgList.take( idx ); }
  virtual KMMsgInfo* setIndexEntry( int idx, KMMessage *msg );
  virtual void clearIndex(bool autoDelete=true, bool syncDict = false);
  virtual void truncateIndex();

  virtual const KMMsgBase* getMsgBase(int idx) const { return mMsgList[idx]; }
  virtual KMMsgBase* getMsgBase(int idx) { return mMsgList[idx]; }

  virtual int find(const KMMsgBase* msg) const { return mMsgList.find((KMMsgBase*)msg); }
  int find( const KMMessage * msg ) const { return FolderStorage::find( msg ); }

  /** Registered unique serial number for the index file */
  int serialIndexId() const { return mIndexId; }

  uchar *indexStreamBasePtr() { return mIndexStreamPtr; }

  bool indexSwapByteOrder() { return mIndexSwapByteOrder; }
  int  indexSizeOfLong() { return mIndexSizeOfLong; }

  virtual TQString indexLocation() const;
  virtual int writeIndex( bool createEmptyIndex = false );

  void recreateIndex( bool readIndexAfterwards = true );
  void silentlyRecreateIndex();

  /** Tests whether the contents of this folder is newer than the index.
      Should return IndexTooOld if the index is older than the contents.
      Should return IndexMissing if there is contents but no index.
      Should return IndexOk if the folder doesn't exist anymore "physically"
      or if the index is not older than the contents.
  */
  virtual IndexStatus indexStatus() = 0;

public slots:
  /** Incrementally update the index if possible else call writeIndex */
  virtual int updateIndex();

protected:
  bool readIndex();

  /** Read index header. Called from within readIndex(). */
  bool readIndexHeader(int *gv=0);

  /** Create index file from messages file and fill the message-info list
      mMsgList. Returns 0 on success and an errno value (see fopen) on
      failure. */
  virtual int createIndexFromContents() = 0;

  bool updateIndexStreamPtr(bool just_close=FALSE);

    /** Inserts messages into the message dictionary by iterating over the
     * message list. The messages will get new serial numbers. This is only
     * used on newly appeared folders, where there is no .ids file yet, or
     * when that has been invalidated. */
  virtual void fillMessageDict();

  /** table of contents file */
  FILE* mIndexStream;
  /** list of index entries or messages */
  KMMsgList mMsgList;

  /** offset of header of index file */
  off_t mHeaderOffset;

  uchar *mIndexStreamPtr;
  int mIndexStreamPtrLength, mIndexId;
  bool mIndexSwapByteOrder; // Index file was written with swapped byte order
  int mIndexSizeOfLong; // Index file was written with longs of this size

private:
  void updateInvitationAndAddressFieldsFromContents();

};

#endif /*kmfolderindex_h*/
