/**********************************************************************
 * Text window module for xtechinfo
 *
 * $Author: brlewis $
 * $Source: /mit/techinfodev/src/xtechinfo/RCS/xtitext.c,v $
 * $Header: /mit/techinfodev/src/xtechinfo/RCS/xtitext.c,v 4.2 95/01/11 15:40:25 brlewis Exp $
 *
 * Copyright 1993 by the Massachusetts Institute of Technology.
 *
 * For copying and distribution information, please see the file
 * <mit-copyright.h>.
 **********************************************************************/
#include <mit-copyright.h>

static char rcsid_text_c[] = "$Header: /mit/techinfodev/src/xtechinfo/RCS/xtitext.c,v 4.2 95/01/11 15:40:25 brlewis Exp $";

#include <stdio.h>
#include <errno.h>
#include <Xm/Xm.h>
#include <Xm/Text.h>
#include <Xm/FileSB.h>
#include <Xm/MessageB.h>
#include <X11/Wc/WcCreate.h>
#include <X11/Xmp/Xmp.h>
#include <ti/ti.h>
#include <ti/memory.h>
#include <com_err.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "xtechinfo.h"
#include "xti.h"

#define ABORT { com_err("xtechinfo", code, "\n%s", ti_context); return; }
#define CString(s) XmStringLtoRCreate((s), XmSTRING_DEFAULT_CHARSET)
#define TString(s,t) XmStringGetLtoR((s),XmSTRING_DEFAULT_CHARSET,(t))

static char *fullname;

void
UnhighlightAll(w)
     Widget w;
{
  XmTextSetHighlight(w, 0, XmTextGetLastPosition(w), XmHIGHLIGHT_NORMAL);
  return;
}

long
HighlightAll(w, searchfor)
     Widget w;
     char *searchfor;
{
  register char *ptr;
  Boolean found = False;
  extern char *textbuf;
  int len;

  len = strlen(searchfor);

  for (ptr = textbuf;
       (ptr = caseindex(ptr, *searchfor)) != NULL;
       ptr++)
    {
      if (!strncasecmp(ptr, searchfor, len))
	{
	  found = True;
	  XmTextSetHighlight (w, (ptr - textbuf), (ptr - textbuf + len),
			      XmHIGHLIGHT_SELECTED);
	}
    }
  if (!found)
    {
      strcpy(ti_context, searchfor);
      return(XTI_ERR_NOSTRING);
    }

  return(0L);
}

long
FindNext(searchfor, position)
     char *searchfor;
     XmTextPosition position;
{
  register char *ptr;
  Boolean found = False;
  int len;
  extern char *textbuf;

  len = strlen(searchfor);

  /* make sure we aren't at end of text */
  if (!textbuf[position]) position=0;

  for (ptr = textbuf+position+1;
       (ptr = caseindex(ptr, *searchfor)) != NULL;
       ptr++)
    {
      if (!strncasecmp(ptr, searchfor, len))
	{
	  found = True;
	  break;
	}
    }
  if (!found)
    {
      /* try from beginning of text */
      if (position) return(FindNext(searchfor, (XmTextPosition)0));
      strcpy(ti_context, searchfor);
      return(XTI_ERR_NOSTRING);
    }

  /* set cursor position */
  XtVaSetValues(glow.text,
		XmNcursorPosition, (XmTextPosition) (ptr - textbuf),
		NULL);
  return(0L);
}

/*ARGSUSED*/
void Find(w, client_data, cbs)
     Widget w;
     XtPointer client_data;
     XmAnyCallbackStruct *cbs;
{
  long code=0L;
  extern char *textbuf;
  char *searchfor = NULL;
  static char prevsearch[256];
  static Boolean searchedbefore = False;
  XmTextPosition cursorpos;
  int len;

  /* find what we're searching for */
  XtVaGetValues(w, XmNvalue, &searchfor, NULL);
  len = strlen(searchfor);

  /* Ignore empty string */
  if (!len)
    {
      UnhighlightAll(glow.text);
      return;
    }

  /* if it's the same as what we searched for before, start search
     at TextSearchPos, otherwise start from beginning. */
  if (!searchedbefore || strcmp(prevsearch, searchfor))
    {
      UnhighlightAll(glow.text);
      code = HighlightAll(glow.text, searchfor);
    }

  /* remember for next time */
  searchedbefore = True;
  strncpy(prevsearch, searchfor, 255);

  if (!code)
    {
      /* find it in the text */
      XtVaGetValues(glow.text,
		    XmNcursorPosition, &cursorpos,
		    NULL);
      code = FindNext(searchfor, cursorpos);
    }

  if (code) XBell(XtDisplay(w), 100);
  return;
}

/**********************************************************************
 * Print
 **********************************************************************/

#define PRINT_COMMAND "enscript -ql"

/*ARGSUSED*/
void Print(w, client_data, cbs)
     Widget w;
     XtPointer client_data;
     XmAnyCallbackStruct *cbs;
{
  long code;

  extern char *textbuf;
  char buf[1024];
  char *printer = NULL;
  FILE *pipe;

  /* get printer from widget */
  XtVaGetValues(glow.printInput, XmNvalue, &printer, NULL);

  /* construct print command */
  strcpy(buf, PRINT_COMMAND);
  if (printer && *printer)
      strcat(strcat(buf, " -P"), printer);

  /* open pipe to print command */
  if ((pipe = popen(buf, "w")) == NULL)
    {
      code = (long) errno;
      strcpy(ti_context, buf);
      ABORT;
    }

  /* print */
  fprintf(pipe, "%s", textbuf);
  pclose(pipe);

  return;
}

/**********************************************************************
 * PrintPrep
 **********************************************************************/

/*ARGSUSED*/
void PrintPrep(w, client_data, cbs)
     Widget w;
     XtPointer client_data;
     XmAnyCallbackStruct *cbs;
{
  int lines=0, pages;
  register char *s;
  extern char *textbuf;
  char buf[1024];

  /* initialize global widget variables */
  if (!glow.printInput)
    {
      glow.printInput = WcFullNameToWidget(w, "*printDialog.input");
      glow.printPages = WcFullNameToWidget(w, "*printDialog.printPages");
      glow.printPrint = WcFullNameToWidget(w, "*printDialog.Print");
    }

  /* count lines */
  for(s=textbuf; *s; s++) if (*s == '\n') lines++;
  pages = (lines+65)/66;

  /* make label */
  sprintf(buf, "%s%d", GlobalResources.str18, pages);
  XtVaSetValues(glow.printPages,
		XmNlabelString, XmStringCreateSimple(buf),
		NULL);

  /* set focus */
  XmProcessTraversal(glow.printInput, XmTRAVERSE_CURRENT);

  return;
}

/**********************************************************************
 * ViewHelp
 **********************************************************************/

/*ARGSUSED*/
void ViewHelp(list_w, client_data, cbs)
     Widget list_w;
     XtPointer client_data;
     XmListCallbackStruct *cbs;
{
  long code;

  if (code=ShowText((ti_node *)0, (char *)client_data)) ABORT;
  return;
}

/**********************************************************************
 * ShowText
 **********************************************************************/

long
ShowText(np, helpfile)
     ti_node *np;
     char *helpfile;
{
  long code;
  static Widget TextWidget = NULL, TextShell = NULL;
  extern char *textbuf;
  ti_recvinfo rcvinfo;
  extern int TextSearchPos;
  int lines=0, pages;
  char string[256];
  register char *s=NULL;
  XmString str1;
  FILE *fp;
  struct stat statbuf;
  char buf[BUFSIZ];
  int nbytes, useless;

  if (np)			/* if showing a document... */
    {
      /* allocate textbuf */
      if (!textbuf)
	{
	  TI_MEM(textbuf = NewArray(char, 1));
	}

      /* get size info */
      if (code = ti_recvbuf(global.menus[global.current]->tp, ti_id(np), 0, 1,
			    textbuf, &rcvinfo)) return(code);
      TI_MEM(textbuf = BiggerArray(char, textbuf, rcvinfo.total+1));

      /* receive text */
      if (code = ti_recvbuf(global.menus[global.current]->tp, ti_id(np), 0,
			    rcvinfo.total, textbuf, &rcvinfo)) return(code);
      textbuf[rcvinfo.total] = '\0';
    }
  else				/* if showing a help file... */
    {
      sprintf(string, "%s/%s", GlobalResources.helpdir, helpfile);
      if ((s = index(string, ':')) != NULL) *s++ = '\0';
      else s = helpfile;

      /* get mod date of file */
      if (stat(string, &statbuf) < 0)
	{
	  strncpy(ti_context, string, 127);
	  return((long) errno);
	}

      /* open file */
      if (!(fp = fopen(string, "r")))
	{
	  strncpy(ti_context, string, 127);
	  return((long) errno);
	}

      /* allocate textbuf */
      if (!textbuf)
	{
	  TI_MEM(textbuf = NewArray(char, statbuf.st_size+1));
	}
      else
	{
	  TI_MEM(textbuf = BiggerArray(char, textbuf, statbuf.st_size+1));
	}
      textbuf[0] = '\0';

      /* get text */
      do
	{
	  if (nbytes = fread(buf, sizeof(char), BUFSIZ, fp))
	    strncat(textbuf, buf, nbytes);
	} while (nbytes == BUFSIZ);
      fclose(fp);
    }

  /* create text form if necessary */
  if (!glow.text || !XtWindow(glow.textshell))
    {
      char dummy_area[1024];

      glow.textshell = XtAppCreateShell("textShell", XTECHINFO_CLASS,
					applicationShellWidgetClass,
					XtDisplay(glow.mainlist),
					NULL, 0 );

      /* Remember this shell as a root widget for WcFullNameToWidget */
      WcRootWidget(glow.textshell);

      /* XXX [SFX: sound of Wcl abstraction barrier breaking] */
      /* create widget tree under this new application shell */
      WcxPostCreate( dummy_area, glow.textshell,  0 );

      /* Realize the widget tree */
      XtRealizeWidget ( glow.textshell );

      glow.text = WcFullNameToWidget(glow.textshell, "*textText");
      glow.textTitle = WcFullNameToWidget(glow.textshell, "*textForm.title");
      glow.textDate = WcFullNameToWidget(glow.textshell, "*textForm.date");
      glow.textPages = WcFullNameToWidget(glow.textshell, "*textForm.pages");
      glow.textFind = WcFullNameToWidget(glow.textshell, "*textForm.findText");
    }

  /* put text into widget */
  UnhighlightAll(glow.text);
  XmTextSetString(glow.text, textbuf);

  /* Clear "Find:" */
  XmTextSetString(glow.textFind, "");

  /* set title */
  if (np)
    XtVaSetValues(glow.textTitle,
		  XmNlabelString, str1=XmStringCreateSimple(ti_title(np)),
		  NULL);
  else
    XtVaSetValues(glow.textTitle,
		  XmNlabelString, str1=XmStringCreateSimple(s),
		  NULL);
  XmStringFree(str1);

  /* count lines */
  for(s=textbuf; *s; s++) if (*s == '\n') lines++;
  pages = (lines+65)/66;
  switch(pages)
    {
    case 0:
    case 1:
      string[0] = '\0';
      break;
    default:
      sprintf(string, "%d %s", pages, GlobalResources.str19);
    }
  XtVaSetValues(glow.textPages,
		XmNlabelString, str1=XmStringCreateSimple(string),
		NULL);
  XmStringFree(str1);

  /* set modify date */
  if (np) strcpy(string, rcvinfo.modified + (strlen(rcvinfo.modified) - 36));
  else sprintf(string, "%s %s", GlobalResources.str20, 
	       (char *)ctime(&statbuf.st_mtime));
  XtVaSetValues(glow.textDate,
		XmNlabelString, str1=XmStringCreateSimple(string),
		NULL);
  XmStringFree(str1);
  
  /* any new searches should start from the beginning of text */
  TextSearchPos = 0;

  /* show window */
  XMapRaised(XtDisplay(glow.textshell), XtWindow(glow.textshell));
  XmProcessTraversal(glow.text, XmTRAVERSE_CURRENT);

  return(0L);
}

/**********************************************************************
 * RemoveExtraMessageBoxButtons
 **********************************************************************/

/*ARGSUSED*/
void RemoveExtraMessageBoxButtons(w, client_data, cbs)
     Widget w;
     XtPointer client_data;
     XmAnyCallbackStruct *cbs;
{
  Widget cancel_buttonG, help_buttonG;

  /* unmap unused buttons */
  if (cancel_buttonG = XmMessageBoxGetChild(w, XmDIALOG_CANCEL_BUTTON))
    XtUnmanageChild(cancel_buttonG);
  if (help_buttonG = XmMessageBoxGetChild(w, XmDIALOG_HELP_BUTTON))
    XtUnmanageChild(help_buttonG);

  return;
}

/**********************************************************************
 * Set Emacs Bindings
 **********************************************************************/

/*ARGSUSED*/
void SetEmacs(w, client_data, cbs)
     Widget w;
     XtPointer client_data;
     XmAnyCallbackStruct *cbs;
{
  MuSetEmacsBindings(w);
  return;
}

/* ----------------------------------------------------------------------------
ResponseCB

DESCRIPTION: Callback
  This is the callback routine for the ok and cancel buttons.
---------------------------------------------------------------------------- */void
ResponseCB(w, text, cb)
     Widget w;
     Widget text;
     XmFileSelectionBoxCallbackStruct *cb;
{
  char *tmpname;
  extern char *textbuf;
  FILE *fp;
  if(!TString(cb->value, &tmpname)){
    return;
  }
  else{
    if((fp = fopen(tmpname,"w")) == NULL)
      return;
    fprintf(fp, textbuf);
    fclose(fp);
  }
}

/* ----------------------------------------------------------------------------HelpPopupCB

DESCRIPTION:
  Here we basically just stick the help dialog into the grab list (to be sure
that we can get input).  This routine should be installed in the popup callbackl
ist of a modal dialog box (to assure that you can still do help).
---------------------------------------------------------------------------- */void
HelpPopupCB(w, clientData, callData)
     Widget w;
     XtPointer clientData;
     XtPointer callData;
{
}

/* ----------------------------------------------------------------------------HelpPopdownCB

DESCRIPTION:
  Here we basically just stick the help dialog into the grab list (to be sure
that we can get input).  This routine should be installed in the popdown
callback list of a modal dialog box.
---------------------------------------------------------------------------- */void
HelpPopdownCB(w, clientData, callData)
     Widget w;
     XtPointer clientData;
     XtPointer callData;
{
}


