/*  File: texthelp.c
 *  Author: Friedemann Wobus (fw@sanger.ac.uk)
 *          and contributions from Darren Platt (daz@sanger.ac.uk)
 *-------------------------------------------------------------------
 * This file is part of the ACEDB genome database package, written by
 * 	Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and
 *	Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr
 *
 * Description:
     contains contains the code to display an HTML page as plain text
     Basic formatting is observed, but images and links are stripped.

 * Exported functions:
 **      helpPrint(char *helpFilename);
 * HISTORY:
 * Last edited: Dec  4 14:33 1998 (fw)
 * * Oct  8 16:01 1998 (fw): removed the declaration of 
			helpOn and help for #define MACINTOSH
 * * Aug 20 16:10 1998 (rd): removed refernces to old help-system
 * * Aug 18 17:17 1998 (fw): help-system split into 
		w1/helpsubs.c  (helpDir, HTML stuff etc).
		w1/texthelp.c  (non-graphical help for tace)
		w2/graphhelp.c (graphical help for xace,image etc.)
 * ----------------------------------------------------------------------
 * ---- major rework, these revision don't necessarily 
 * ---- affect code still left in this file
 * ----------------------------------------------------------------------
 * * May  2 01:07 1996 (rd): new implementation of 
                       helpMakeIndex() using filDirectory()
 * * May  2 18:24 1996 (mieg):
         fall back on oldhelp
         callMosaic if (http:)
         use freeout for server
         jaime's file name rotation
         remaining problem: help topic in tace should be case-insensitive
 * * May  1 18:24 1996 (fw): fixed freePage() to avoid mem leaks
 * * Apr 30 16:18 1996 (fw): fixed #ifdef NON_GRAPHICs for tace
 * * Apr 30 16:18 1996 (fw): added image dictionary
 * * Apr 29 12:37 1996 (fw): added handling of <DL> lists
 * * Apr 25 16:27 1996 (fw): added <IMG > tag
 * * Apr 22 17:43 1996 (fw): changed help system to HTML browser
 * Created: Thu Feb 20 14:49:50 1992 (mieg)
 *-------------------------------------------------------------------
 */

/* $Id: texthelp.c,v 1.1 2002/11/14 20:00:06 lstein Exp $ */

#ifndef MACINTOSH
/********************************************************************/
#include "help_.h"
#include "freeout.h"
/********************************************************************/
static void htmlPagePrint (HtmlPage *page);
static void printTextSection (HtmlNode *node);

/********************************************************************/
static char buf[10000] ;	/* text-buffer for wordwrapping */

/********************************************************************/

static float xPos ;
static int indent ;
static int WINX ;


/* dumps out help-page without images and markups */
UTIL_FUNC_DEF BOOL helpPrint (char *helpFilename)
/* returns TRUE if a help page could successfully be displayed
   for the given subject, returns FALSE if no such page found */
{
  HtmlPage *page ;
  Array dirList;
  char *cp;
  int i,n,x;

 if ((page = htmlPageCreate (helpFilename)))
   {
     /* found a page */
     htmlPagePrint (page);
     
     htmlPageDestroy (page);

     return TRUE;
   }

  if (!helpFilename)
    freeOut ("Help subject not found\n");
  else
    freeOut ("Help subject is ambiguous\n");

  freeOut ("Try:\n  help\n");
      
  /* now show a list of possible files */
  if(!(dirList = filDirectoryCreate
       (helpGetDir(), HELP_FILE_EXTENSION, "r")) )
    {
      messout ("Can't open help directory %s\n"
	       "(%s)",
	       helpGetDir(), messSysErrorText()) ;
      return FALSE ;
    }
  
  for (i = 0, x = 0 ; i < arrayMax(dirList) ; i++)
    {
      cp = arr(dirList,i,char*) ;
      if (!cp || !*cp || !strlen(cp))
	continue ;
      if (helpFilename)
	{
	  if (strncasecmp(filGetFilename(helpFilename),cp,
			  strlen(filGetFilename(helpFilename))) != 0)
	    continue;
	}

      n = strlen(cp) ;
      if (n > 5 && !strcmp("."HELP_FILE_EXTENSION,cp + n - 5))
	*(cp + n - 5) = 0 ; 

      x += n + 1 ;
      if (x > 50) { x = n + 1 ; freeOut("\n") ;}
      freeOutf("%s  ", cp) ;
    }
  freeOut("\n") ;

  filDirectoryDestroy (dirList);

  return FALSE;
} /* helpPrint */


/************************************************************/
/* counter-part to graphWebBrowser(), which remote-controls 
   netscape using the -remote command line option. Useful
   for textual applications running in an X11 environment,
   where x-apps can be called from within the application,
   but the Xtoolkit (used to drive netscape via X-atoms)
   shouldn't be linked in, because it is a textual app. */
/************************************************************/
UTIL_FUNC_DEF BOOL  helpWebBrowser(char *link)
{
  /* currently impossible, because it is hard to find out whether
     a netscape process is already running.
     Stupidly enough 'netscape -remote...' doesn't exit
     with code 1, if it can't connect to an existing process
*/
  return FALSE;
} /* helpWebBrowser */





/************************************************************/
/******************                   ***********************/
/****************** static functions  ***********************/
/******************                   ***********************/
/************************************************************/


static void htmlPagePrint (HtmlPage *page)
{
  /* init screen-position parameters */

  WINX = 80 ;
  indent = 2 ;
  xPos = indent ;

  /* start recursivle printing nodes */
  printTextSection (page->root) ;

  return;
} /* htmlPagePrint */
/************************************************************/


static void newTextLine (void)
{
  int i ;
  
/*  if (xPos != indent)*/
    {
      freeOut("\n") ;
      for (i = 0; i < indent; ++i) freeOut (" ") ;
      xPos = indent ;
    }
} /* newLine */
/************************************************************/

static void blankTextLine (void)
{
  int i ;

  freeOut("\n") ;
  for (i = 0; i < indent; ++i) freeOut (" ") ;
  xPos = indent ;

  newTextLine () ;
} /* newLine */
/************************************************************/

static void printTextSection (HtmlNode *node)
/* part specific to the text-help system, which uses freeOut
   to print arsed HTML as plain text */
{
  int i, len ;
  char *cp, *start ;
  static BOOL 
    MODE_PREFORMAT=FALSE, 
    MODE_HREF=FALSE,
    MODE_HEADER=FALSE, 
    FOUND_NOBULLET_IN_LIST_NOINDENT=FALSE ;
  static int itemNumber ;
  static char *currentLink ;

  switch (node->type)
    {
    case HTML_SECTION:
      printTextSection (node->left) ;
      if (node->right) printTextSection (node->right) ;
      break ;
    case HTML_COMMENT:
      /* do nothing */
      break ;
    case HTML_DOC:
    case HTML_HEAD:
    case HTML_BODY:
      if (node->left) printTextSection (node->left) ;
      break ;
    case HTML_TITLE:
      for (i = 0; i < strlen(node->text)+4; ++i)
	freeOutf ("*") ;
      freeOutf ("\n* %s *\n", node->text) ;
      for (i = 0; i < strlen(node->text)+4; ++i)
	freeOutf ("*") ;
      blankTextLine() ;
      break ;
    case HTML_HEADER:
      {
	MODE_HEADER = TRUE ;

	indent = node->hlevel*2 ;

	blankTextLine () ;
	
	/* check, in case some bozo has done a thing like <H1></H1> */
	if (node->left) printTextSection (node->left) ; 

	freeOutf ("\n") ;
	for (i = 0; i < xPos; ++i)
	  {
	    if (i < indent) freeOutf (" ") ;
	    else  freeOutf ("*") ;
	  }

	blankTextLine () ;
	
	MODE_HEADER = FALSE ;
      }
      break ;

    case HTML_LIST:
      if (node->lstyle == HTML_LIST_BULLET || 
	  node->lstyle == HTML_LIST_NUMBER)
	indent += 2 ;
      else if (node->lstyle == HTML_LIST_NOINDENT)
	indent -= 2 ;
      newTextLine () ;

      itemNumber = 0 ;

      /* a list might not have a leftnode (a list item) */
      if (node->left) printTextSection (node->left) ;

      if (node->lstyle == HTML_LIST_BULLET || 
	  node->lstyle == HTML_LIST_NUMBER)
	indent -= 2 ;
      else if (node->lstyle == HTML_LIST_NOINDENT)
	indent += 2 ;
      if (node->lstyle == HTML_LIST_NOINDENT &&
	  FOUND_NOBULLET_IN_LIST_NOINDENT)
	{
	  indent -= 4 ;
	  FOUND_NOBULLET_IN_LIST_NOINDENT = FALSE ;
	}

      blankTextLine () ;
      break ;

    case HTML_LISTITEM:
      ++itemNumber ;
      if (node->left)
	{
	  if (node->lstyle == HTML_LIST_NOINDENT_NOBULLET)
	    {
	      /* if we are in a <DL> list and went to indentation
		 because of a <DD> item, a <DT> item brings back
		 the old indent-level (noindent for <DL>'s) */
	      if (FOUND_NOBULLET_IN_LIST_NOINDENT)
		{
		  indent -= 6 ;
		  FOUND_NOBULLET_IN_LIST_NOINDENT = FALSE ;
		  newTextLine () ;
		  freeOutf ("  ") ;
		}
	    }
	  else
	    newTextLine () ;
	  if (node->lstyle == HTML_LIST_BULLET ||
	      node->lstyle == HTML_LIST_NOINDENT)
	    {
	      freeOutf ("* ") ;
	      indent += 2 ;
	      xPos  = indent ;
	    }
	  else if (node->lstyle == HTML_LIST_NUMBER)
	    {
	      freeOutf ("%d. ", itemNumber) ;
	      indent += strlen(messprintf ("%d. ", itemNumber)) ;
	      xPos  = indent ;
	    }
	  else if (node->lstyle == HTML_LIST_NOBULLET)
	    {
	      /* part of a <DL> noindented list, but a <DD>
		 item becomes indented, but no bullet */
	      /* if we come across the first NO_BULLET item, in
		 a LIST_NOINDENT, the LIST becomes indented */
	      if (!FOUND_NOBULLET_IN_LIST_NOINDENT)
		{
		  indent += 6 ;
		  xPos = indent ;
		  freeOutf ("      ") ;
		  fflush (stdout) ;

		  FOUND_NOBULLET_IN_LIST_NOINDENT = TRUE ;
		}
	    }
	  printTextSection (node->left) ;
	}
      if (node->lstyle == HTML_LIST_BULLET ||
	  node->lstyle == HTML_LIST_NOINDENT)
	{
	  indent -= 2 ;
	}
      else if (node->lstyle == HTML_LIST_NUMBER)
	{
	  indent -= strlen(messprintf ("%d. ", itemNumber)) ;
	}
      else if (node->lstyle == HTML_LIST_NOBULLET)
	{
	  if (!FOUND_NOBULLET_IN_LIST_NOINDENT)
	    indent -= 6 ;
	}
      
      if (node->right)
	{
	  printTextSection (node->right) ;
	}
      break ;

    case HTML_HREF:
      if (node->link)
	{
	  MODE_HREF = TRUE ;
	  currentLink = node->link ;
	}
      /* we have to check for leftnode, in case we have a thing
	 like <A HREF=...></A>. The HREF-node doesn't have a TEXT
	 node attached, and it would crash otherwise */
      if (node->left)printTextSection (node->left) ; 

      if (node->link)
	{
	  MODE_HREF = FALSE ;
	  currentLink = 0 ;
	}
      break ;
    case HTML_TEXT:
      cp = node->text ;
      if (!MODE_PREFORMAT)
	stripSpaces (node->text) ;
      /* for MODE_PREFORMAT keeps all controls chars */

      while (*cp)
	{
	  len = 0 ;
	  start = cp ;
	  
	  if (!MODE_PREFORMAT)
	    {
	      while (*cp && !isspace((int)*cp)) { ++(cp) ; ++len ; }
	      if (*cp) ++cp ;	/* skip whitespace */
	    }
	  else
	    {
	      while (*cp && *cp != '\n') { ++(cp) ; ++len ; }
	      if (*cp) 
		{
		  ++cp ;	/* skip RETURN */
		  ++len ;	/* so we copy the RETURN into buf */
		}
	    }

	  memset (buf, 0, 10000) ;
	  strncpy (buf, start, len) ;
	  buf[len] = 0 ;

	  /* linewrapping of words/lines longer than WINX */
	  if (strlen(buf) > WINX)
	    {
	      cp = start + (int)(WINX) ;
	      buf[(int)WINX] = 0 ;
	      len = (int)WINX ;
	    }
	  
	  /* word wrapping if not in preformatting mode */
	  if (!MODE_PREFORMAT)
	    {
	      if (xPos != indent)  /* not at start of line ... */
		{
		  xPos += 1 ;	   /* ... one space before the word */
		  freeOutf (" ") ;
		  fflush (stdout) ;
		}
	      if (xPos + len > WINX)
		{
		  newTextLine () ;
		}
	      freeOutf ("%s", buf) ;
	      xPos += strlen(buf) ; /* place xPos at the end of word */
	    }
	  else if (MODE_PREFORMAT)
	    {
	      int oldpos, stringpos, screenpos, ii ;
	      i = 0 ;

	      /* replace TABs with appropriate number of spaces */
	      while (buf[i])
		{
		  if (buf[i] == '\t')
		    {
		      /* oldpos is the position, that this TAB char
			 would go on the screen without TABifying
			 NOTE: xPos is always at least "indent" 
			 (to leave a left margin) */
		      oldpos = (xPos - indent) + i ;

		       /* screenpos is the position of the TAB char 
			  after inserting spaces
			  NOTE: the TAB itself will be
			  overwritten by one space */
		      screenpos = (((oldpos/8)+1)*8) - 1 ;

		       /* stringpos is where the TAB should go
			  in the string, where it'll turn into a space
			  at that position */
		      stringpos = screenpos - (xPos-indent) ;

		      /* shift all text from current position "i"
			 onwards */
		      for (ii = strlen(buf)-1; ii >= i ; --ii)
			buf[ii+(stringpos-i)] = buf[ii] ;

		      /* fill gap with spaces and also overwrite TAB
			 with a space */
		      for (ii = i; ii <= stringpos; ++ii)
			buf[ii] = ' ' ;

		      i = stringpos ;
		    }
		  ++i ;
		}

      /* don't use len, it might have changed when inserting spaces */
	      if (buf[strlen(buf)-1] == '\n')
		{
		  buf[strlen(buf)-1] = 0 ;
		  freeOutf ("%s", buf) ;
		  xPos += strlen(buf) ;
		  newTextLine ();	/* for the '\n' */
		}
	      else
		{
		  freeOutf ("%s", buf) ;
		  xPos += strlen(buf) ;
		}
	    }
	}
      break ;
    case HTML_GIFIMAGE:
      {
	freeOutf (" [IMAGE] ") ;
	xPos += 9 ;
      }
      break ;
    case HTML_NOIMAGE:
      break ;
    case HTML_RULER:
      {
	newTextLine () ;
	for (i = indent; i < WINX; ++i)
	  freeOutf ("-") ;
	xPos = WINX ;
	newTextLine () ;
      }
      break ;
    case HTML_PARAGRAPH:
      blankTextLine () ;
      break ;
    case HTML_LINEBREAK:
      newTextLine () ;
      break ;
    case HTML_BOLD_STYLE:
    case HTML_STRONG_STYLE:
      {
	if (node->left)	printTextSection (node->left) ;
      }
      break ;
    case HTML_ITALIC_STYLE:
      {
	if (node->left) printTextSection (node->left) ;
      }
      break ;
    case HTML_CODE_STYLE:
      {
	if (node->left)	printTextSection (node->left) ;
      }
      break ;
    case HTML_STARTBLOCKQUOTE:
      newTextLine () ;
      indent += 3 ;
      xPos = indent ;
      for (i = 0; i < indent; ++i) freeOutf (" ") ;
      fflush (stdout) ;
      break ;
    case HTML_ENDBLOCKQUOTE:
      indent -= 3 ;
      blankTextLine () ;
      break ;
    case HTML_STARTPREFORMAT:
      MODE_PREFORMAT = TRUE ;
      newTextLine () ;
      break ;
    case HTML_ENDPREFORMAT:
      MODE_PREFORMAT = FALSE ;
      break ;
    case HTML_UNKNOWN:
      break;			/* compiler happiness */
    }
} /* printTextSection */
/************************************************************/

#endif /* !def MACINTOSH */