/*
 * $Id: wvclass.h 1.3 1996/08/13 03:46:40 brydon Exp $
 */

/*
 *
 *  WinVN C++ class definitions
 *
 */

#ifndef WVCLASS_H
#define WVCLASS_H

//#define WHEREAMI(s) TRACE3("TRACE %s: Executing %s, line %d\n", s, __FILE__, __LINE__)

//#define DEBUGMEMUSAGE  1 // detailed memory mgmt debug info

#define POOLBLOCKSIZE 4096

// C++ Implementation of aligned memory pool class of varying size

struct NewStruct
{
#ifdef DEBUGMEMUSAGE
  int16 iSeqCtr;
#endif
  //int16 iUsedSize;
  int16 iAllocSize;
};


class WMemPool // 335
{
public:  // member functions
  WMemPool(size_t uElementSize, unsigned uNumElements);
  inline void* AllocElement();
  inline void FreeElement(void*p);
  ~WMemPool();
private:
  void AllocBlock();

private:  // data
  unsigned m_uElmSize; // do not change the order of these
  unsigned m_uBlkSize; // two declarations (see constructor)
  struct MemPoolElement
  {
    MemPoolElement* next;
  };
  struct MemPoolBlock
  {
    MemPoolBlock*next;
    MemPoolElement pe;
  };
  MemPoolElement* m_FreeList;
  MemPoolBlock* m_pBlock;
};


inline void* WMemPool::AllocElement()
{
  if(!m_FreeList)
  {
    AllocBlock();
  }
  MemPoolElement* pe = m_FreeList;
  if(pe)
  {
    m_FreeList = pe->next;
  }
  return pe;
}


inline void WMemPool::FreeElement(void*p)
{
#ifdef DEBUGMEMUSAGE
  if(!p)
    DEBUG_BREAK;
#endif
  MemPoolElement*pe = (MemPoolElement*)p;
  pe->next = m_FreeList;
  m_FreeList = pe;
}


class WVString
{
protected:
  char*m_data;
private:
  static WMemPool m_ClassPool;
public:
  WVString(const char*s=0, const size_t uLen = 0);
  WVString(const WVString&rhs);
  WVString(const WVString&lhs, const WVString&rhs);
  ~WVString();
  void*operator new(size_t size);
  void operator delete(void*p);
  WVString& operator=(const WVString& rhs);
  WVString& operator=(const char* rhs);
  WVString& operator+=(const WVString& rhs);
  WVString& operator+=(const char* rhs);
  inline operator const char*()const  // (const char*) cast
  { return m_data;}
  
  //inline char operator[](int idx) const //         c = s[idx]; (rvalue/value)
  //{ return m_data[idx];}
  
  inline const char& operator[](int idx) const //  c = s[idx]; (rvalue/ref)
  { return m_data[idx];}
  
  inline char& operator[](int idx)      //         s[idx] = c; (lvalue)
  { return m_data[idx];}
  
  // unsigned Length() const;
  friend BOOL operator ==(const WVString& lhs, const WVString& rhs);
  friend BOOL operator !=(const WVString& lhs, const WVString& rhs);
  friend WVString operator+(const WVString& lhs, const WVString& rhs);
  friend WVString operator+(const WVString& lhs, const char* rhs);
  friend WVString operator+(const char* lhs, const WVString& rhs);
protected:
  size_t AllocSize();
};


inline BOOL operator ==(const WVString& lhs, const WVString& rhs)
{ return strcmp(lhs.m_data, rhs.m_data) == 0;}

inline BOOL operator !=(const WVString& lhs, const WVString& rhs)
{ return !(lhs == rhs);}

inline WVString operator+(const WVString& lhs, const WVString& rhs)
{ return WVString(lhs, rhs);}

inline WVString operator+(const WVString& lhs, const char* rhs)
{ return WVString(lhs, WVString(rhs));}

inline WVString operator+(const char* lhs, const WVString& rhs)
{ return WVString(WVString(lhs), rhs);}


class WVPersBOOL  // persistent BOOL class
{
private:
  static WMemPool m_ClassPool;
protected:
  BOOL m_bModified;
  WVString m_sSection;
  WVString m_sKey;
  BOOL m_bValue;
public:
  WVPersBOOL(const char*sGroup, const char*sSection, BOOL bDefault = FALSE);
  ~WVPersBOOL();
  inline void*operator new(size_t size)
  { return m_ClassPool.AllocElement(); }
  inline void operator delete(void*p)
  { m_ClassPool.FreeElement(p); }
  WVPersBOOL& operator=(const WVPersBOOL& rhs);
  WVPersBOOL& operator=(const BOOL rhs);
  WVPersBOOL& operator|=(const BOOL rhs);
  WVPersBOOL& operator&=(const BOOL rhs);
  inline operator const BOOL()const  // const BOOL cast
  { return m_bValue;}
private:
  WVPersBOOL();             // not implemented
  WVPersBOOL(const char*s); // not implemented
};


class WVHeaderData
{
private:
  static WMemPool m_ClassPool;
public:
  unsigned long iGroups;
  time_t date;
  WVString sSubject;
  WVString sFrom;
  WVString sEmail;
  WVString sMessage_id;
  WVString sBest_ref;
  WVString sFrob_ref_list;
  WVString sNewsgroups;
public:
  WVHeaderData(unsigned long i=0, time_t t=0) : iGroups(i), date(t) {}
  inline void*operator new(size_t size)
  { return m_ClassPool.AllocElement(); }
  inline void operator delete(void*p)
  { m_ClassPool.FreeElement(p); }
};

/* the size of this struct *must* be a power of two for win16.  'huge' */
/* arrays require this. */
/* (4 4 4 2 1 1) => 16 */

typedef struct {
  TypDoc *ArtDoc;
  WVHeaderData *pHD;
  unsigned long number;
  unsigned short int lines;
  char SeenSelected;
  char thread_depth;
} TypHeader;


typedef TypHeader huge *header_p;


typedef struct LATESTSTRUCT {
  unsigned int lines;
  unsigned int iGroups;
  WVString sFrom;
  WVString sEmail;
  WVString sSubject;
  WVString sMessage_id;
  WVString sNewsgroups;
} LATEST;


extern LATEST Latest;

// Action/Killfile constants
#define AA_NOACTION_MASK               1
#define AA_LT_MASK                     2
#define AA_EQ_MASK                     3
#define AA_GT_MASK                     4
#define AA_IS_MASK                     5
#define AA_CONTAINS_MASK               6
#define AA_SELECT_MASK            0x1000
#define AA_MODULO                 0x0010

#define NO_ACTION                      1
#define MARK_SEEN_ART_LINES_BASE       1 * AA_MODULO  // 0x10/16
#define MARK_SEEN_ART_LINES_LT          MARK_SEEN_ART_LINES_BASE + AA_LT_MASK
#define MARK_SEEN_ART_LINES_EQ          MARK_SEEN_ART_LINES_BASE + AA_EQ_MASK
#define MARK_SEEN_ART_LINES_GT          MARK_SEEN_ART_LINES_BASE + AA_GT_MASK
#define MARK_SEEN_ART_GROUPS_BASE      2 * AA_MODULO  // 0x20/32
#define MARK_SEEN_ART_GROUPS_LT         MARK_SEEN_ART_GROUPS_BASE + AA_LT_MASK
#define MARK_SEEN_ART_GROUPS_EQ         MARK_SEEN_ART_GROUPS_BASE + AA_EQ_MASK
#define MARK_SEEN_ART_GROUPS_GT         MARK_SEEN_ART_GROUPS_BASE + AA_GT_MASK
#define MARK_SEEN_ART_FROM_BASE        3 * AA_MODULO  // 0x30/48
#define MARK_SEEN_ART_FROM_IS           MARK_SEEN_ART_FROM_BASE + AA_IS_MASK
#define MARK_SEEN_ART_FROM_CONTAINS     MARK_SEEN_ART_FROM_BASE + AA_CONTAINS_MASK
#define MARK_SEEN_ART_EMAIL_BASE       4 * AA_MODULO  // 0x40/64
#define MARK_SEEN_ART_EMAIL_IS          MARK_SEEN_ART_EMAIL_BASE + AA_IS_MASK
#define MARK_SEEN_ART_EMAIL_CONTAINS    MARK_SEEN_ART_EMAIL_BASE + AA_CONTAINS_MASK
#define MARK_SEEN_ART_SUBJ_BASE        5 * AA_MODULO  // 0x50/80
#define MARK_SEEN_ART_SUBJ_IS           MARK_SEEN_ART_SUBJ_BASE + AA_IS_MASK
#define MARK_SEEN_ART_SUBJ_CONTAINS     MARK_SEEN_ART_SUBJ_BASE + AA_CONTAINS_MASK
#define MARK_SEEN_ART_MSGID_BASE       6 * AA_MODULO  // 0x60/96
#define MARK_SEEN_ART_MSGID_IS          MARK_SEEN_ART_MSGID_BASE + AA_IS_MASK
#define MARK_SEEN_ART_MSGID_CONTAINS    MARK_SEEN_ART_MSGID_BASE + AA_CONTAINS_MASK
#define MARK_SEEN_ART_REF_BASE         7 * AA_MODULO  // 0x70/112
//#define MARK_SEEN_ART_REF_IS            MARK_SEEN_ART_REF_BASE + AA_IS_MASK
#define MARK_SEEN_ART_REF_CONTAINS      MARK_SEEN_ART_REF_BASE + AA_CONTAINS_MASK
#define MARK_SEEN_NGROUP_BASE          8 * AA_MODULO  // 0x80/128
//#define MARK_SEEN_NGROUP_IS             MARK_SEEN_NGROUP_BASE + AA_IS_MASK
#define MARK_SEEN_NGROUP_CONTAINS       MARK_SEEN_NGROUP_BASE + AA_CONTAINS_MASK
#define SELECT_ART_LINES_BASE           AA_SELECT_MASK + MARK_SEEN_ART_LINES_BASE
#define SELECT_ART_LINES_LT             AA_SELECT_MASK + MARK_SEEN_ART_LINES_LT
#define SELECT_ART_LINES_EQ             AA_SELECT_MASK + MARK_SEEN_ART_LINES_EQ
#define SELECT_ART_LINES_GT             AA_SELECT_MASK + MARK_SEEN_ART_LINES_GT
#define SELECT_ART_GROUPS_BASE          AA_SELECT_MASK + MARK_SEEN_ART_GROUPS_BASE
#define SELECT_ART_GROUPS_LT            AA_SELECT_MASK + MARK_SEEN_ART_GROUPS_LT
#define SELECT_ART_GROUPS_EQ            AA_SELECT_MASK + MARK_SEEN_ART_GROUPS_EQ
#define SELECT_ART_GROUPS_GT            AA_SELECT_MASK + MARK_SEEN_ART_GROUPS_GT
#define SELECT_ART_FROM_BASE            AA_SELECT_MASK + MARK_SEEN_ART_FROM_BASE
#define SELECT_ART_FROM_IS              AA_SELECT_MASK + MARK_SEEN_ART_FROM_IS
#define SELECT_ART_FROM_CONTAINS        AA_SELECT_MASK + MARK_SEEN_ART_FROM_CONTAINS
#define SELECT_ART_EMAIL_BASE           AA_SELECT_MASK + MARK_SEEN_ART_EMAIL_BASE
#define SELECT_ART_EMAIL_IS             AA_SELECT_MASK + MARK_SEEN_ART_EMAIL_IS
#define SELECT_ART_EMAIL_CONTAINS       AA_SELECT_MASK + MARK_SEEN_ART_EMAIL_CONTAINS
#define SELECT_ART_SUBJ_BASE            AA_SELECT_MASK + MARK_SEEN_ART_SUBJ_BASE
#define SELECT_ART_SUBJ_IS              AA_SELECT_MASK + MARK_SEEN_ART_SUBJ_IS
#define SELECT_ART_SUBJ_CONTAINS        AA_SELECT_MASK + MARK_SEEN_ART_SUBJ_CONTAINS
#define SELECT_ART_MSGID_BASE           AA_SELECT_MASK + MARK_SEEN_ART_MSGID_BASE
#define SELECT_ART_MSGID_IS             AA_SELECT_MASK + MARK_SEEN_ART_MSGID_IS
#define SELECT_ART_MSGID_CONTAINS       AA_SELECT_MASK + MARK_SEEN_ART_MSGID_CONTAINS
#define SELECT_ART_REF_BASE             AA_SELECT_MASK + MARK_SEEN_ART_REF_BASE
//#define SELECT_ART_REF_IS               AA_SELECT_MASK + MARK_SEEN_ART_REF_IS
#define SELECT_ART_REF_CONTAINS         AA_SELECT_MASK + MARK_SEEN_ART_REF_CONTAINS
#define SELECT_NGROUP_BASE              AA_SELECT_MASK + MARK_SEEN_NGROUP_BASE
//#define SELECT_NGROUP_IS                AA_SELECT_MASK + MARK_SEEN_NGROUP_IS
#define SELECT_NGROUP_CONTAINS          AA_SELECT_MASK + MARK_SEEN_NGROUP_CONTAINS


typedef struct tag_ad
{
  int iAction;
  long int iParam;
  char *sParam;
} ACTIONDATA, FAR *LPACTIONDATA;


struct Node
{
  Node * Flink;
  Node * Blink;
  ACTIONDATA ad;
};


// WVArticleAction - 'killfile' et al
class WVArticleAction
{
protected:
  Node *m_Head;
  Node *m_Tail;
  Node *m_Current;
  //char m_ProfSect[128];
  WVString m_sProfSect;
  WVPersBOOL *m_bNeedGroup;
private:
  static WMemPool m_ClassPool;
public:
  //WVArticleAction();
  WVArticleAction(const char*sGrp);
  WVArticleAction(const WVArticleAction& wv);
  WVArticleAction(WVArticleAction*wv);
  ~WVArticleAction();
  inline void*operator new(size_t size)
  { return m_ClassPool.AllocElement(); }
  inline void operator delete(void*p)
  { m_ClassPool.FreeElement(p); }
  void SetIParam(int i);
  void SetParamText(const char*sP);
  void ResetCurrent(){m_Current = m_Head;};
  void ReadActions(/* const char*sGroup */);
  void WriteActions();
  Node*GetCurrent(){return m_Current;};
  void Append(int iA, long int iP, const char*sP);
  void DeleteNode(Node* pN);
  void DeleteAll();
  void GoToNext();
  void GoToPrev();
  void Switch(Node*nA, Node*nB);
  void Switchwith(WVArticleAction*nB);
  void ActOnArticles(TypGroup far *Group, header_p headers);
  BOOL NeedNgroupHeader();
private:
  WVArticleAction& operator=(const WVArticleAction& rhs); // unimplemented
  WVArticleAction* operator&();                           // unimplemented
  const WVArticleAction* operator&() const;               // unimplemented
};

//extern WVArticleAction g_action;
extern WVArticleAction *g_pAction;


class WVSeenDB
{
private:
  uint32 m_uLowVal, m_uHiVal;
  uint32 m_uLowBase, m_uHiBase;
  unsigned int*m_pBitmap; // intentionally different for Win16 and Win32
  static WMemPool m_ClassPool;
#ifdef _WIN32      // This mess and the stuff
  enum{BMSIZE=32}; // that uses it is to
#else              // workaround a Win16 bug
  enum{BMSIZE=16}; // with the "<<" operator
#endif

public:
  WVSeenDB(uint32 uLo, uint32 uHi, const WVSeenDB*sdb = NULL);
  ~WVSeenDB()
  { delete m_pBitmap; }
  inline void*operator new(size_t size)
  { return m_ClassPool.AllocElement(); }
  inline void operator delete(void*p)
  { m_ClassPool.FreeElement(p); }
  void GetRange(TypRange& r);
  void MarkSeen(uint32 uArtIdx);
  void MarkSeen(uint32 uArtIdx1, uint32 uArtIdx2);
  void MarkUnseen(uint32 uArtIdx);
  BOOL WasSeen(uint32 uArtIdx);
  uint32 NumUnseen();
  uint32 HighestSeen();
  uint32 LowestUnseen();
private:
  WVSeenDB(); // not implemented
};

#define RangeOffset(nlen) (((nlen+sizeof(int))/sizeof(int))*sizeof(int)+sizeof(TypGroup))

#define CalcGroupLen(Group) (sizeof (TypLine) + RangeOffset (Group->NameLen) + sizeof (int))

/* in wvgroup.cpp    */
extern "C" 
BOOL article_operation (TypDoc far * Doc, long artindex,BOOL (*art_fun) (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex));
extern "C" 
BOOL selected_false (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
void SetGroupSelections (TypDoc * MyDoc, header_p headers, long newActive);
long search_headers (TypDoc far * HeaderDoc, header_p headers, long artindex, long num_headers);
void SaveSelectedArts (HWND hwnd, TypDoc far * Doc, header_p headers, long num_headers);
BOOL toggle_read_unread (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
BOOL toggle_selected (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
BOOL selected_true (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
BOOL seen_true (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
BOOL seen_false (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
BOOL mark_read_to_here (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
BOOL mark_read_all (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
BOOL mark_read_selected (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
BOOL mark_selected_read_articles (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
BOOL mark_selected_unread_articles (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
BOOL mark_deselected_read_articles (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
BOOL mark_deselected_unread_articles (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
BOOL SelectHeader (TypDoc far * Doc, header_p header, BOOL value);

void SeverArticleParent(TypDoc *doc);
void setArticleFocus (HWND hWndArt);
long NewCursorToTextLine (int X, int Y, TypDoc far * DocPtr);
long AffectSelected (TypDoc far * Doc, BOOL value, BOOL compare);
long AffectSelectedOnScreen (TypDoc far * Doc, BOOL value, BOOL compare);
void InitiateReceiveArticle (TypDoc far * Doc, char far * articleId);
BOOL mark_unread_selected (TypDoc far * Doc, header_p headers, TypGroup * group, long artindex);
//void CloseGroupWnd (HWND hWnd, TypDoc far * ThisDoc);
void SetMenusForMultiArticleOperation (TypDoc far * DocPtr, int enable);

/* in file wvart.cpp */
long find_article_by_subject (TypHeader huge * headers, long artindex, long num_headers);
void view_article_by_message_id (TypDoc * Doc, char far * msg_id, long artindex);
void SetArticleRot13Mode (HWND hWnd, BOOL RotMode);
//BOOL GetArticleRot13Mode (HWND hWnd);
void mark_article_seen(TypDoc FAR * Doc, char * groupname, long artindex);
void CloseArtWnd (HWND hWnd, TypDoc * ThisDoc);
void UpdateHighlightedText (TypDoc far * DocPtr, TextSelect far * PreviousPos);
void HighlightText (TypDoc far * DocPtrs);
void CopyTextToClipBoard (TypDoc FAR * DocPtr);

/* in file headarry.cpp */
header_p header_elt (header_p headers, long index);
header_p lock_headers (HANDLE header_handle, HANDLE thread_handle);
void unlock_headers (HANDLE header_handle, HANDLE thread_handle);
void free_headers (HANDLE header_handle, HANDLE thread_handle);
void sort_by_option(header_p h, thread_array t, BOOL tOk, unsigned int nL, HANDLE hHandle, HANDLE tHandle);
//void sort_by_threads (HANDLE header_handle, HANDLE thread_handle, long length);
void initialize_header_array (HANDLE header_handle, HANDLE thread_handle, long length);
void set_index_to_identity (HANDLE header_handle, HANDLE thread_handle, long length);
void shell_sort_index_array (header_p headers, thread_array index, long nElements,
                 int (*compare) (header_p headers, long elem1, long elem2));
//int compare_subject (header_p headers, long elem1, long elem2);
//int compare_date (header_p headers, long elem1, long elem2);
//int compare_lines (header_p headers, long elem1, long elem2);
//int compare_from (header_p headers, long elem1, long elem2);
//int compare_artnum (header_p headers, long elem1, long elem2);

#endif
