/*---  wvart.c ------------------------------------------- */
/*  This file contains the window procedure for the Article Viewing window
 *  for WinVn.
 */

#include "windows.h"
#ifndef MAC
#include "winundoc.h"
#endif
#include "WVglob.h"
#include "WinVn.h"

long find_article_by_subject (TypHeader far *headers,long artindex,long num_headers);
int cursor_to_char_number (int X, int Y,TypDoc *DocPtr,TypBlock far **BlockPtr,TypLine far **LinePtr);
void view_article_by_message_id (TypDoc *Doc, char far *article_request, long artindex);

long
find_article_by_subject (TypHeader far *headers,
				long artindex,
				long num_headers)
{
char far *subject = headers[artindex++].subject;

	do {
		if (lstrcmpi (headers[artindex].subject, subject) == 0)
		return (artindex);		/* return the index */
	} while (artindex++ < num_headers);

	return (-1);			/* not found */
}

/****************************************************************************

    FUNCTION: WinVnArtWndProc(HWND, unsigned, WORD, LONG)

    PURPOSE:  Processes messages

****************************************************************************/

long FAR PASCAL 
WinVnArtWndProc (hWnd, message, wParam, lParam)
     HWND hWnd;
     unsigned message;
     WPARAM wParam;
     LPARAM lParam;
{
  FARPROC lpProcAbout;
  HMENU hMenu;

  PAINTSTRUCT ps;		/* paint structure          */

  HDC hDC;			/* handle to display context */
  RECT myRect;			/* selection rectangle      */
  HWND hWndView;
  HDC hDCView;
  TypDoc *ThisDoc;
  TypGroup far *GroupDoc;
  int ih, j;
  int found, X, Y, charnum;
  int imemo;
  int CtrlState;
  TypLine far *LinePtr, far * ArtLinePtr;
  TypBlock far *BlockPtr, far * ArtBlockPtr;
  HANDLE hBlock;
  char mybuf[MAXINTERNALLINE];
  unsigned int Offset;
  int reply;
  int result;
  char far *cptr;
  char far *textptr;
  int textlen;
  TypLineID MyLineID;
  HANDLE header_handle;
  TypHeader * headers;
  long header_num;

#ifdef MAC
  int vRef;
#endif

  for (ih = 0, found = FALSE; !found && ih < MAXARTICLEWNDS; ih++)
    {
      if (ArticleDocs[ih].hDocWnd == hWnd)
	{
	  found = TRUE;
	  ThisDoc = &(ArticleDocs[ih]);
	}
    }

  if (!found)
    {
      ThisDoc = CommDoc;
    }


  switch (message)
    {

    case WM_ACTIVATE:
    case WM_SETFOCUS:
      if (wParam)
	{
	  ActiveArticleDoc = ThisDoc;
	}
      /* fall through */
    case WM_SYSCOMMAND:
      return (DefWindowProc (hWnd, message, wParam, lParam));

    case WM_SIZE:
      GetClientRect (hWnd, &myRect);
      ThisDoc->ScXWidth = myRect.right;
      ThisDoc->ScYHeight = myRect.bottom;
      ThisDoc->ScYLines = (myRect.bottom - myRect.top - TopSpace) / ArtLineHeight;
      ThisDoc->ScXChars = (myRect.right - myRect.left - SideSpace) / ArtCharWidth;
      break;


    case WM_DESTROY:
      ThisDoc->InUse = FALSE;
      if (ThisDoc == CommDoc)
	{
	  CommBusy = FALSE;
	  CommDoc = (TypDoc *) NULL;
	}
      /* Clear the pointer in the line for this article in the   */
      /* group  document.  This pointer currently points       */
      /* to the current document, which we are wiping out      */
      /* with the destruction of this window.                  */

      if (ThisDoc->ParentDoc)
	{
       	LockLine (ThisDoc->ParentDoc->hParentBlock,
       	          ThisDoc->ParentDoc->ParentOffset,
       	          ThisDoc->ParentDoc->ParentLineID,
       	          &BlockPtr, &LinePtr);

	GroupDoc = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));

	header_handle = GroupDoc->header_handle;
	headers = (TypHeader *) ((char *) GlobalLock (header_handle) + sizeof(char *)) ;

	headers[ThisDoc->LastSeenLineID].ArtDoc = (TypDoc *) NULL;
	UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
	GlobalUnlock (header_handle);
	}
      /* Clear document                                        */
      FreeDoc (ThisDoc);

      /* If there's another article window, make it the active   */
      /* artcile window so we don't create a new one if the      */
      /* New Article flag is FALSE.                              */

      for (j = MAXARTICLEWNDS - 1; j >= 0; j--)
	{
	  if (ArticleDocs[j].InUse)
	    {
	      ActiveArticleDoc = &(ArticleDocs[j]);
	      break;
	    }
	}
      break;

    case WM_KEYDOWN:
      /* See if this key should be mapped to a scrolling event
       * for which we have programmed the mouse.  If so,
       * construct the appropriate mouse call and call the mouse code.
       */
#ifndef MAC
      if (wParam == VK_F6)
	{
	  NextWindow (ThisDoc);
	}
      else
	{
	  CtrlState = GetKeyState (VK_CONTROL) < 0;
	  for (j = 0; j < NUMKEYS; j++)
	    {
	      if (wParam == key2scroll[j].wVirtKey &&
		  CtrlState == key2scroll[j].CtlState)
		{
		  SendMessage (hWnd, key2scroll[j].iMessage,
			       key2scroll[j].wRequest, 0L);
		  break;
		}
	    }
	}
#endif
      break;

    case WM_LBUTTONDBLCLK:
      X = LOWORD (lParam);
      Y = HIWORD (lParam);

      charnum = cursor_to_char_number (X,Y,ThisDoc,&BlockPtr,&LinePtr);

      if (charnum >= 0) {
        textlen = ((TypText far *) ((char far *) LinePtr +
                                sizeof (TypLine)))->NameLen;

        textptr = (char far *) ((char far *) LinePtr +
     	                      sizeof (TypLine) + sizeof (TypText) );

        if (textlen)
        {					/* find a message-id */
          char far *start, far *end;

          for (start = textptr + charnum; start >= textptr; start--) 
            if (*start == '<') break;

          for (end = textptr + charnum; end < (textptr + textlen); end++) 
            if (*end == '>') break;

          if ((start >= textptr) && (end < (textptr + textlen))) {
            sprintf (str, "ARTICLE %.*Fs\r", (int) ((long) end - (long) start + 1), start);
            LockLine (ThisDoc->ParentDoc->hParentBlock,
                           ThisDoc->ParentDoc->ParentOffset,
		           ThisDoc->ParentDoc->ParentLineID,
		           &BlockPtr, &LinePtr);
            GroupDoc = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
            view_article_by_message_id (ThisDoc->ParentDoc, str, ThisDoc->LastSeenLineID);
          }
        }
      }

      break;

    case WM_VSCROLL:
      ScrollIt (ThisDoc, wParam, lParam);
      break;

    case WM_PAINT:
      {
	HANDLE hBlock;
	unsigned int Offset, MyLen, width;
	int VertLines, HorzChars;
	int EndofDoc = FALSE;
	int RangeHigh, CurPos;
	int RestX;
	char far *textptr;
	TypArticle far *MyArt;
	TypBlock far *BlockPtr;
	TypLine far *LinePtr;
	HANDLE hBlackBrush;
	DWORD MyColors[4], MyBack[4];
	int MyColorMask = 1, PrevColorMask = MyColorMask;
	SIZE string_size;
#ifdef MAC
	RECT myRect;
	POINT myPoint;
#endif

	hDC = BeginPaint (hWnd, &ps);

	GetClientRect (hWnd, &myRect);
	SelectObject (hDC, hFontArt);
	VertLines = ThisDoc->ScYLines;
	HorzChars = ThisDoc->ScXChars;

	LockLine (ThisDoc->hCurTopScBlock, ThisDoc->TopScOffset, ThisDoc->TopScLineID,
		  &BlockPtr, &LinePtr);

	/* Update the scroll bar thumb position.                 */

	CurPos = ThisDoc->TopLineOrd;
	if (CurPos < 0)
	  CurPos = 0;
	RangeHigh = ThisDoc->TotalLines - VertLines;
	if (RangeHigh < 0)
	  RangeHigh = 0;
	SetScrollRange (hWnd, SB_VERT, 0, RangeHigh, FALSE);
	SetScrollPos (hWnd, SB_VERT, CurPos, TRUE);
#ifdef MAC
	myRect.right = ThisDoc->DocClipRect.right;
	myRect.top = 0;
	myRect.bottom = ArtLineHeight;
#endif
	/* Now paint this stuff on the screen for debugging. */

	X = SideSpace;
	Y = StartPen;

	if (LinePtr->length != END_OF_BLOCK)
	  do
	    {
	      MyLen = LinePtr->length - sizeof (TypLine) - sizeof (int) - 1;
	      MyLen = ((TypText far *) ((char far *) LinePtr +
					sizeof (TypLine)))->NameLen;
	      textptr = (char far *) LinePtr + sizeof (TypLine) + sizeof (TypText);

	      /* Now write out the line.                            */

#if 1
	      GetTextExtentPoint (hDC, textptr, MyLen, &string_size);

	      width = string_size.cx;
#else
	      width = ArtCharWidth * MyLen;
#endif
	      TextOut (hDC, X, Y, textptr, MyLen);
#ifdef MAC
	      GetPen (&myPoint);
	      myRect.left = myPoint.h;
	      FillRect (&myRect, white);

	      myRect.top += ArtLineHeight;
	      myRect.bottom += ArtLineHeight;
#else
	      RestX = X + width;
	      PatBlt (hDC, RestX, Y, myRect.right - RestX, ArtLineHeight, PATCOPY);
#endif
#if 0
	      if (MyLen < HorzChars)
		{
		  RestX = X + width;
#if 0
		  TextOut (hDC, RestX, Y, Blanks, MAXINTERNALLINE);
#endif
		  PatBlt (hDC, RestX, Y, myRect.right - RestX, ArtLineHeight, PATCOPY);
		}
#endif
	      Y += ArtLineHeight;
	    }
	  while (--VertLines > 0 && NextLine (&BlockPtr, &LinePtr));

	/* We've reached the end of the data to be displayed     */
	/* on this window.  If there's more screen real estate   */
	/* left, just blank it out.                              */

#if !MAC
	PatBlt (hDC, 0, Y, myRect.right, myRect.bottom - Y, PATCOPY);
#else
	/* myRect.top = myRect.top + ArtLineHeight; */
	myRect.bottom = ThisDoc->DocClipRect.bottom;
	myRect.left = 0;
	EraseRect (&myRect);
#endif
#if 0
	while (VertLines-- > -1)
	  {
	    TextOut (hDC, X, Y, Blanks, HorzChars);
	    Y += ArtLineHeight;
	  }
#endif

	UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
	EndPaint (hWnd, &ps);
	break;
      }

    case WM_COMMAND:
      switch (wParam)
	{

	case IDM_EXIT:
	  DestroyWindow (hWnd);
	  break;

	case IDM_SAVE:
	  if (strcmp (SaveArtFileName, ""))
	    {
	      SaveArtAppend = TRUE;
	      MRRWriteDocument (ActiveArticleDoc, sizeof (TypText), SaveArtFileName, SaveArtvRef, SaveArtAppend);
	      /* Should the 0 be sizeof(TypText) ? */
	      break;
	    }
	  else
	    {
	      goto saveas;
	    }

	case IDM_SAVEAS:
	saveas:;
#ifndef MAC
	  if (DialogBox (hInst, "WinVnSaveArt", hWnd, lpfnWinVnSaveArtDlg))
	    {
	      InvalidateRect (hWnd, NULL, TRUE);
	    }
#else
	  result = MySaveAs (SaveArtFileName, &SaveArtvRef, &SaveArtAppend);
	  if (result)
	    {
	      MRRWriteDocument (ActiveArticleDoc, sizeof (TypText), SaveArtFileName, SaveArtvRef, SaveArtAppend);
	    }
#endif
	  break;

	case IDM_FIND_NEXT_SAME:
	case IDM_NEXT_ARTICLE:

		if (ThisDoc->ParentDoc)
		{
			LockLine (ThisDoc->ParentDoc->hParentBlock,
			          ThisDoc->ParentDoc->ParentOffset,
			          ThisDoc->ParentDoc->ParentLineID,
			          &BlockPtr, &LinePtr);

			GroupDoc = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));

			if (wParam == IDM_FIND_NEXT_SAME) {
				header_handle = GroupDoc->header_handle;
				headers = (TypHeader far *) ((char *)GlobalLock (header_handle) + sizeof(char *)) ;

				header_num = find_article_by_subject (headers,ThisDoc->LastSeenLineID,GroupDoc->total_headers - 1);

				GlobalUnlock (header_handle);
				if (header_num >= 0)
				ViewArticle (ThisDoc->ParentDoc, header_num, TRUE);
				else MessageBox (hWnd, "No more articles", "That's all!", MB_OK); 
			}

			else {

				if (GroupDoc)
				{
				  if (ThisDoc->LastSeenLineID < (GroupDoc->total_headers - 1) )
				    ViewArticle (ThisDoc->ParentDoc, ThisDoc->LastSeenLineID + 1, TRUE);
				  else MessageBox (hWnd, "No more articles", "That's all!", MB_OK);
				}
				else MessageBox (hWnd, "Sorry--you must have the group window around\n\for me to be able to find the next article", "Can't find next article", MB_OK);
			UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
			}
		}
		else MessageBox (hWnd, "That Group's window is gone.  Reopen it.", "Error", MB_OK);

          break;

	case IDM_FOLLOWUP:
	  CreatePostingWnd (ThisDoc, DOCTYPE_POSTING);
	  break;

	case IDM_MAIL:
	  CreatePostingWnd (ThisDoc, DOCTYPE_MAIL);
	  break;

	case IDM_SEARCH:

	  FindDoc = ThisDoc;

	  if (DialogBox (hInst, "WinVnFind", hWnd, lpfnWinVnFindDlg))
	    {
	      found = DoFind (TRUE);
	      if (!found)
		{
		  strcpy (mybuf, "\"");
		  strcat (mybuf, FindDoc->SearchStr);
		  strcat (mybuf, "\" not found.");
		  MessageBox (hWnd, mybuf, "Not found", MB_OK);
		}
	    }

	  break;

	case IDM_SEARCH_NEXT:

	  FindDoc = ThisDoc;
	  if (strcmp (FindDoc->SearchStr, ""))
	    {
	      found = DoFind (FALSE);
	      if (!found)
		{
		  strcpy (mybuf, "\"");
		  strcat (mybuf, FindDoc->SearchStr);
		  strcat (mybuf, "\" not found.");
		  MessageBox (hWnd, mybuf, "No more occurrences", MB_OK);
		}
	    }
	  break;

	}

	break;

    default:
      return (DefWindowProc (hWnd, message, wParam, lParam));
    }
  return (0);
}









