/* wvaddhdr.cpp V 1.0  1997/04/25 00:00:00 heirich */
/*********************************************************************
 *
 * Module: WVADDHDR.CPP
 *
 * send bugreports to <winvn@heirich.in-berlin.de>
 *
 * a lot of code is taken from wvaction.cpp
 * Purpose: support for automatic adding of headers
 * Version 1.0
 *********************************************************************/
/*********************************************************************
 * Notes:
 *
 *********************************************************************/
/*********************************************************************
 * Changelog:
 *
 * V 1.0        initial release
 *
 *********************************************************************/

#include <windows.h>
#include <windowsx.h>
#include "wvglob.h"
#include "winvn.h"
#pragma hdrstop
#include "wvclass.h"


#define MAXADDHEADERS 100


static struct ValStrTable DocTypeTable[] =
{
  0,                            "----",
  DOCTYPE_POSTING,              "P---",
  DOCTYPE_POSTING+
  DOCTYPE_MAIL,                 "PM--",
  DOCTYPE_POSTING+
  DOCTYPE_CANCEL,               "P-C-",
  DOCTYPE_POSTING+
  DOCTYPE_FORWARD,              "P--F",
  DOCTYPE_POSTING+
  DOCTYPE_MAIL+
  DOCTYPE_CANCEL,               "PMC-",
  DOCTYPE_POSTING+
  DOCTYPE_CANCEL+
  DOCTYPE_FORWARD,              "P-CF",
  DOCTYPE_POSTING+
  DOCTYPE_MAIL+
  DOCTYPE_FORWARD,              "PM-F",
  DOCTYPE_POSTING+
  DOCTYPE_MAIL+
  DOCTYPE_CANCEL+
  DOCTYPE_FORWARD,              "PMCF",
  
  DOCTYPE_MAIL,                 "-M--",
  DOCTYPE_MAIL+
  DOCTYPE_CANCEL,               "-MC-",
  DOCTYPE_MAIL+
  DOCTYPE_FORWARD,              "-M-F",
  DOCTYPE_MAIL+
  DOCTYPE_CANCEL+
  DOCTYPE_FORWARD,              "-MCF",
  
  DOCTYPE_CANCEL,               "--C-",
  DOCTYPE_CANCEL+
  DOCTYPE_FORWARD,              "--CF",
  
  DOCTYPE_FORWARD,              "---F"
};

#define DOCTYPETABLESIZE (sizeof(DocTypeTable) / sizeof(DocTypeTable[0]))


WMemPool WVAddHdr::m_ClassPool(sizeof(WVAddHdr), 4096/sizeof(WVAddHdr)); 
WVAddHdr *g_pAddHdr = NULL;  // global variable for 'all groups'


WVAddHdr::WVAddHdr(const char*sGrp)
: m_Head(NULL), m_Tail(NULL), m_Current(NULL)
{
  char sProfSect[128];
  if(sGrp)
    sprintf(sProfSect, "G: %s", sGrp);
  else
    sprintf(sProfSect, "N: %s", NNTPHost);
  m_sProfSect = sProfSect;
}


WVAddHdr::WVAddHdr(WVAddHdr*wv)
: m_Head(NULL), m_Tail(NULL), m_Current(NULL),
  m_sProfSect(wv->m_sProfSect)
{
  if(wv->m_Head == NULL)
    return;
  AHNode*n = wv->m_Head;
  do
  {
    Append(n->ahd.iParam,n->ahd.sParam);
    n = n->Flink;
  } while(n != NULL);
}


WVAddHdr::WVAddHdr(const WVAddHdr&wv)
: m_Head(NULL), m_Tail(NULL), m_Current(NULL),
  m_sProfSect(wv.m_sProfSect)
{
  if(wv.m_Head == NULL)
    return;
  AHNode*n = wv.m_Head;
  do
  {
    Append(n->ahd.iParam,n->ahd.sParam);
    n = n->Flink;
  } while(n != NULL);
}


WVAddHdr::~WVAddHdr()
{
  DeleteAll();
}

// Append a new entry to the end of the list
void WVAddHdr::Append(int i,const char*sP)
{
  AHNode * n = new AHNode;
  if(n)
  {
    if(m_Tail == NULL)
    {
      m_Head = n;
      n->Blink = NULL;
    }
    else
    {
      m_Tail->Flink = n;
      n->Blink = m_Tail;
    }
    m_Tail = n;
    m_Current = n;
    n->Flink = NULL;
    n->ahd.iParam = i;
    n->ahd.sParam = NULL;
    SetParamText(sP);
  }
}


void WVAddHdr::DeleteNode(AHNode* pN)
{
  if(pN == NULL)
    return;
  AHNode*pF = pN->Flink;
  AHNode*pB = pN->Blink;

  if(pN->Blink && pN->Flink) // any node in middle of list
  {
    pF->Blink = pB;
    pB->Flink = pF;
  }
  else
  {
    if(pN->Blink == NULL) // first node in list
    {
      m_Head = pN->Flink;
      if(pN->Flink != NULL)
      {
        pF->Blink = NULL;
      }
    }
    if(pN->Flink == NULL) // last node in list
    {
      m_Tail = pN->Blink;
      if(pN->Blink != NULL)
      {
        pB->Flink = NULL;
      }
    }
  }
  delete pN;
  m_Current = pB ? pB : pF;
}

// Set the iParam value
void WVAddHdr::SetIParam(int i)
{
  if(m_Current)
  {
    m_Current->ahd.iParam = i;
  }
}

// Set the sParam value
void WVAddHdr::SetParamText(const char*sP)
{
  if(m_Current)
  {
    if((sP == NULL ) || !*sP)
    {
      if(m_Current->ahd.sParam)
      {
        delete m_Current->ahd.sParam;
        m_Current->ahd.sParam = NULL;
      }
    }
    else
    {
      if(m_Current->ahd.sParam)
      {
        if(strlen(m_Current->ahd.sParam) < strlen(sP))
        {
          delete m_Current->ahd.sParam;
          m_Current->ahd.sParam = NULL;
        }
      }
      if(m_Current->ahd.sParam == NULL)
      {
        m_Current->ahd.sParam = new char[strlen(sP) + 1];
      }
      strcpy(m_Current->ahd.sParam, sP);
    }
  }
}



// Delete all entries on the list
void WVAddHdr::DeleteAll()
{
  m_Current = m_Head;
  while(m_Current != NULL)
  {
    m_Head = m_Current->Flink;
    delete m_Current->ahd.sParam;
    m_Current->ahd.sParam = NULL;
    m_Current->Flink = NULL;
    m_Current->Blink = NULL;
    delete m_Current;
    m_Current = m_Head;
  }
  m_Head = NULL;
  m_Tail = NULL;
  m_Current = NULL;
}


// Go to the next node in the linked list
void WVAddHdr::GoToNext()
{
  if(m_Current != NULL)
  {
    m_Current = m_Current->Flink;
  }
}


// Go to the previous node in the linked list
void WVAddHdr::GoToPrev()
{
  if(m_Current != NULL)
  {
    m_Current = m_Current->Blink;
  }
}


// Switch two nodes in the linked list
void WVAddHdr::Switch(AHNode*nA, AHNode*nB)
{
  char*sTmp;
  int iTmp;

  if(!nA)
    return;
  if(!nB)
    return;
  iTmp = nA->ahd.iParam;
  nA->ahd.iParam = nB->ahd.iParam;
  nB->ahd.iParam = iTmp;
  sTmp = nA->ahd.sParam;
  nA->ahd.sParam = nB->ahd.sParam;
  nB->ahd.sParam = sTmp;
}


// Switch two complete lists
void WVAddHdr::Switchwith(WVAddHdr*pA)
{
  AHNode*pWTmp;

  if(!pA)
    return;
  pWTmp = this->m_Head;
  this->m_Head = pA->m_Head;
  pA->m_Head = pWTmp;
  pWTmp = this->m_Tail;
  this->m_Tail = pA->m_Tail;
  pA->m_Tail = pWTmp;
  pWTmp = this->m_Current;
  this->m_Current = pA->m_Current;
  pA->m_Current = pWTmp;
}


// Read the list of additional headers from the .ini file
void WVAddHdr::ReadAddHdr(/* const char*sGroup */)
{
	char ProfEntry[32];
	char ProfValue[MAXHEADERLINE];
	char *pParam;

	for(int ind = 1; ind < MAXADDHEADERS; ind++)
	{
		sprintf(ProfEntry, "AddHdr%02d", ind);

		if(!GetPrivateProfileString(m_sProfSect, ProfEntry, "", 
									ProfValue, sizeof(ProfValue), szAppProFile))
			return;

		//trim spaces from end of string
		pParam = &ProfValue[strlen(ProfValue)];
		while (--pParam >= ProfValue)
			if (*pParam != ' ')
				break;
		pParam++;
		*pParam = '\0';

		//terminate string at first space found anywhere in string (skip apply flags)
		if ((pParam = strchr(ProfValue, ' ')) != NULL)
			*pParam++ = '\0';
		
		//skip any following spaces
		while ((pParam) && (*pParam == ' '))
			pParam++;
		
		//save header string
		if ((pParam) && (*pParam))
		{
			for(int i = 1; i < DOCTYPETABLESIZE; i++) 
			{
				if(!strcmp(ProfValue, DocTypeTable[i].text))
				{
					Append(DocTypeTable[i].value, pParam);
					break;
				}
			}
		}
	}
}


// Save the additional headers back to the .ini file
void WVAddHdr::WriteAddHdr()
{
  int ind = 0;
  AHNode* cur;
  char ProfEntry[32];
  char ProfValue[MAXHEADERLINE];
  
  ResetCurrent();

  while((cur = GetCurrent())!= NULL)
  {
    if(cur->ahd.sParam)
    {
      for(int i = 1; i < DOCTYPETABLESIZE; i++)
      {
        if(cur->ahd.iParam == DocTypeTable[i].value)
        {
          sprintf(ProfEntry, "AddHdr%02d", ++ind);
          sprintf(ProfValue, "%s %s", DocTypeTable[i].text, cur->ahd.sParam);
#ifdef _DEBUG
          if(strlen(ProfValue) >= sizeof(ProfValue)) // bozo programmer filter
            DEBUG_BREAK;
#endif
          ProfValue[sizeof(ProfValue)-1] = 0;
          WritePrivateProfileString(m_sProfSect, ProfEntry,
            ProfValue, szAppProFile);
          break;
        }
      }
    }
    GoToNext();
  }
  sprintf(ProfEntry, "AddHdr%02d", ++ind);
  // TODO: if WIN32, use the Registry...
  WritePrivateProfileString(m_sProfSect, ProfEntry, NULL, szAppProFile);
}

BOOL WVAddHdr::GetParamText(char*sP)
{
  if(m_Current)
  {
    strcpy(sP,m_Current->ahd.sParam);
    return TRUE;
  }
  return FALSE;
}

BOOL WVAddHdr::GetIParam(int *p)
{
  if(m_Current)
  {
      *p = m_Current->ahd.iParam;
      return TRUE;
  }
  return FALSE;
}


void ResetGlobalAddHdr()
{
    if (g_pAddHdr) {
        g_pAddHdr->ResetCurrent();
    }
}

void GlobalGoToNextAddHdr()
{
    if (g_pAddHdr) {
        g_pAddHdr->GoToNext();
    }
}

BOOL GetGlobalCurrentAddHdr(int *p,char *str)
{
    if (g_pAddHdr) {
       if (g_pAddHdr->GetParamText(str))
         return g_pAddHdr->GetIParam(p);
       
    }
    return FALSE;
}


void FindGroupAddHdr(WVAddHdr **ppAddHdr,TypDoc * Doc)
{
    TypBlock far *BlockPtr;
    TypLine far *LinePtr;
    TypGroup far *Group;
    HANDLE hBlock;
    unsigned int Offset;
    TypLineID MyLineID;
    
    *ppAddHdr = (WVAddHdr *) NULL;
    
    while (Doc && (Doc->DocType != DOCTYPE_GROUP))
      Doc = Doc->ParentDoc;
    if (Doc && LockLine (Doc->hParentBlock, Doc->ParentOffset,Doc->ParentLineID,
         &BlockPtr, &LinePtr)) {
         Group = GetGroup(LinePtr);
         *ppAddHdr = Group->pAddHdr;
         UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
    }
}


void ResetGroupAddHdr(TypDoc *Doc)
{
    WVAddHdr * pAddHdr;

    FindGroupAddHdr(&pAddHdr,Doc);
    if (pAddHdr) {
        pAddHdr->ResetCurrent();
    }
}

void GroupGoToNextAddHdr(TypDoc *Doc)
{
    WVAddHdr * pAddHdr;

    FindGroupAddHdr(&pAddHdr,Doc);
    if (pAddHdr) {
        pAddHdr->GoToNext();
    }
}

BOOL GetGroupCurrentAddHdr(TypDoc *Doc,int *p, char *str)
{
    WVAddHdr * pAddHdr;

    FindGroupAddHdr(&pAddHdr,Doc);
    if (pAddHdr) {
       if (pAddHdr->GetParamText(str))
          return pAddHdr->GetIParam(p);
    }
    return FALSE;
}
