/* $XConsortium: TextScroll.c /main/4 1995/07/15 21:02:31 drk $ */
/*
 *  @OPENGROUP_COPYRIGHT@
 *  COPYRIGHT NOTICE
 *  Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc.
 *  Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group
 *  ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for
 *  the full copyright text.
 *  
 *  This software is subject to an open license. It may only be
 *  used on, with or for operating systems which are themselves open
 *  source systems. You must contact The Open Group for a license
 *  allowing distribution and sublicensing of this software on, with,
 *  or for operating systems which are not Open Source programs.
 *  
 *  See http://www.opengroup.org/openmotif/license for full
 *  details of the license agreement. Any use, reproduction, or
 *  distribution of the program constitutes recipient's acceptance of
 *  this agreement.
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
 *  PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 *  WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
 *  OR FITNESS FOR A PARTICULAR PURPOSE
 *  
 *  EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
 *  NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
 *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED
 *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
 *  EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGES.
 */
/*
 * HISTORY
 */

/*  Standard C headers  */
#include <stdio.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>

/*  X headers  */
#include <X11/Xlib.h>
#include <X11/StringDefs.h>
#include <X11/Xatom.h>

#include <testlib.h>

#define	NUM_COLUMNS		80
#define	NUM_ROWS		24
#define	MAX_LINE_LEN	512
#define	MAX_NAME_LEN	255

#define	DEFAULT_IN_FILE1	"./RowCol1_1.c"
#define	DEFAULT_IN_FILE2	"./WordWrap.dat"

#define	TEXT1_X		10
#define	TEXT1_Y		10


static void	fill_text_buf();
static void  	fillTextCB();
static void  	quitCB();
static void  	scrollToEndCB();
static void  	scrollToBeginCB();
static void 	PrintLapseTime();


/*  Global Variables  */

char infile_name[MAX_NAME_LEN + 1];
char *text_string;
char *small_text_string = "SMALL TEXT";

Widget Form1;
Widget Text1;
Widget fillText;
Widget scrollToBegin;
Widget scrollToEnd;

int	total_lines = 0;
Boolean show_perf_bug = False;
Boolean word_wrap_on = False;
Boolean test_word_wrap = False;


XmFontList	newfontlist;
XFontStruct	*newfont;

Arg args[MAX_ARGS];
int n;
FILE	*in_fp;
FILE	*outfp;
int		in_fd;


main (argc, argv)
int argc;
char **argv;
{

	Widget	quit;
	char        name[80];

	struct timeval act_time1, act_time2;
	struct timezone zone_time1, zone_time2;


	infile_name[0] = '\0';

	/*  initialize toolkit  */
    CommonTestInit(argc, argv);

	if (UserData != NULL)
		ProcessCommandArgs();

    sprintf(name, "%s.out", argv[0]);
    if ((outfp = fopen(name, "w+")) == NULL) {

        fprintf(stderr, "Can not open output file %s.out. Trying in /tmp\n",
                argv[0]);
        sprintf(name, "/tmp/%s.out", argv[0]);
        if ((outfp = fopen(name, "w+")) == NULL) {
            fprintf(stderr, "Can not open output file /tmp/%s.out. Exiting\n",
                    argv[0]);
            exit(0);
        }

	}

    n = 0;
	XtSetArg(args[n], XtNwidth, 800);  n++;
	XtSetArg(args[n], XtNheight, 500);  n++;
    XtSetValues(Shell1, args, n);

	XtRealizeWidget(Shell1);
    

	/* create main form */
	n = 0;
	Form1 = XmCreateForm (Shell1, "Form1", args, n);
	XtManageChild (Form1);

	/* Read the text file into a buffer */
	fill_text_buf();

	/* create multi line text widget */
	n = 0;
	XtSetArg(args[n], XmNx, TEXT1_X); n++;
	newfont = XLoadQueryFont(XtDisplay(Shell1),"9x15");
	if (newfont != NULL) {
		newfontlist = XmFontListCreate(newfont, XmSTRING_DEFAULT_CHARSET);
		XtSetArg(args[n], XmNfontList, newfontlist);  n++;
	}
	XtSetArg(args[n], XmNcolumns, NUM_COLUMNS);  n++;
	XtSetArg(args[n], XmNrows, NUM_ROWS);  n++;
	XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
	XtSetArg(args[n], XmNscrollHorizontal, False); n++;
	XtSetArg(args[n], XmNeditable, False); n++;
    if (word_wrap_on == True) {
		XtSetArg(args[n], XmNwordWrap, True); n++;
	}
    if (show_perf_bug == True) {
    	XtSetArg(args[n], XmNresizeWidth, True); n++;
    	XtSetArg(args[n], XmNresizeHeight, True); n++;
	}
    Text1 = XmCreateScrolledText(Form1, "Text1", args, n);
    if (show_perf_bug == True) {

        gettimeofday(&act_time1, &zone_time1);
        XmTextSetString(Text1, text_string);
        gettimeofday(&act_time2, &zone_time2);
        fprintf(outfp, "Time lapsed to set TextString before Manage : \n");
        PrintLapseTime(outfp, &act_time1, &act_time2);

    }

	XtManageChild(Text1);

	n = 0;
	XtSetArg(args[n], XmNx, 10); n++;
	XtSetArg(args[n], XmNy, TEXT1_Y + 400); n++;
	quit = XmCreatePushButtonGadget(Form1, "Quit", args, n);
	XtManageChild(quit);
	XtAddCallback(quit, XmNactivateCallback, quitCB, NULL);

	n = 0;
	XtSetArg(args[n], XmNx, 150); n++;
	XtSetArg(args[n], XmNy, TEXT1_Y + 400); n++;
        if (show_perf_bug == True) {
                XtSetArg(args[n], XmNsensitive, False); n++;
        }
	fillText = XmCreatePushButtonGadget(Form1, "Fill Text", args, n);
	XtManageChild(fillText);
	XtAddCallback(fillText, XmNactivateCallback, fillTextCB, NULL);

	n = 0;
	XtSetArg(args[n], XmNx, 300); n++;
	XtSetArg(args[n], XmNy, TEXT1_Y + 400); n++;
        if (show_perf_bug == False) {
                XtSetArg(args[n], XmNsensitive, False); n++;
        }
	scrollToEnd = XmCreatePushButtonGadget(Form1, "Scroll To End", args, n);
	XtManageChild(scrollToEnd);
	XtAddCallback(scrollToEnd, XmNactivateCallback, scrollToEndCB, NULL);

	n = 0;
	XtSetArg(args[n], XmNx, 450); n++;
	XtSetArg(args[n], XmNy, TEXT1_Y + 400); n++;
        if (show_perf_bug == False) {
                XtSetArg(args[n], XmNsensitive, False); n++;
        }
	scrollToBegin = XmCreatePushButtonGadget(Form1, "Scroll To Begin", args, n);
	XtManageChild(scrollToBegin);
	XtAddCallback(scrollToBegin, XmNactivateCallback, scrollToBeginCB, NULL);

	if (word_wrap_on == True)
		fprintf(outfp, "wordWrap is ON\n");
	else
		fprintf(outfp, "wordWrap is OFF\n");

	XtRealizeWidget(Shell1);

        CommonPause();
        CommonPause();
	XtAppMainLoop(app_context);
}


static void PrintLapseTime(fp, first,second)
FILE	*fp;
struct timeval *first, *second;
{
     struct timeval lapsed;

     if (first->tv_usec > second->tv_usec) {
        second->tv_usec += 1000000;
        second->tv_sec--;
     }

     lapsed.tv_usec = second->tv_usec - first->tv_usec;
     lapsed.tv_sec = second->tv_sec - first->tv_sec;

     fprintf(fp, "lapsed time = %d.%06d sec\n\n",
            lapsed.tv_sec, lapsed.tv_usec%1000000);
     fflush(fp);

}


static void  quitCB(w, client_data, call_data)
Widget	w;
caddr_t  client_data;
caddr_t  call_data;
{

	int	i;

	XtFree(text_string);
	XtDestroyWidget(Shell1);
	fflush(outfp);
	fclose(outfp);
	exit(0);

}


static void  fillTextCB(w, client_data, call_data)
Widget	w;
caddr_t  client_data;
caddr_t  call_data;
{

	struct timeval act_time1, act_time2;
	struct timezone zone_time1, zone_time2;


	if (Text1 == NULL)
		return;

	fprintf(outfp, "Total Number of Lines in the textfile : %d\n\n", 
			total_lines);

	gettimeofday(&act_time1, &zone_time1);
	XmTextSetString(Text1, text_string);
	gettimeofday(&act_time2, &zone_time2);
	fprintf(outfp, "Time lapsed to set TextString : \n");
	PrintLapseTime(outfp, &act_time1, &act_time2);

	n = 0;
    XtSetArg(args[n], XmNsensitive, True); n++;
	XtSetValues(scrollToEnd, args, n);

}


static void  scrollToEndCB(w, client_data, call_data)
Widget	w;
caddr_t  client_data;
caddr_t  call_data;
{

	struct timeval act_time1, act_time2;
	struct timezone zone_time1, zone_time2;


	if (Text1 == NULL)
		return;

	gettimeofday(&act_time1, &zone_time1);
	XmTextScroll(Text1, total_lines - NUM_ROWS);
	gettimeofday(&act_time2, &zone_time2);
	fprintf(outfp, "Time lapsed scrolling to end of textfile : \n");
	PrintLapseTime(outfp, &act_time1, &act_time2);

	n = 0;
    XtSetArg(args[n], XmNsensitive, False); n++;
	XtSetValues(scrollToEnd, args, n);
	n = 0;
    XtSetArg(args[n], XmNsensitive, True); n++;
	XtSetValues(scrollToBegin, args, n);


}


static void  scrollToBeginCB(w, client_data, call_data)
Widget	w;
caddr_t  client_data;
caddr_t  call_data;
{

	struct timeval act_time1, act_time2;
	struct timezone zone_time1, zone_time2;


	if (Text1 == NULL)
		return;

	gettimeofday(&act_time1, &zone_time1);
	XmTextScroll(Text1, -(total_lines - NUM_ROWS));
	gettimeofday(&act_time2, &zone_time2);
	fprintf(outfp, "Time lapsed scrolling to beginning of textfile : \n");
	PrintLapseTime(outfp, &act_time1, &act_time2);

	n = 0;
    XtSetArg(args[n], XmNsensitive, False); n++;
	XtSetValues(scrollToBegin, args, n);
	n = 0;
    XtSetArg(args[n], XmNsensitive, True); n++;
	XtSetValues(scrollToEnd, args, n);

}


static void	fill_text_buf()
{

	struct stat	stat_buf;
	int	filesize, bytes_read;
	char	line[MAX_LINE_LEN + 1];

	if (infile_name[0] == '\0')
        {
            if ( test_word_wrap )
		strcpy(infile_name, DEFAULT_IN_FILE2);
            else
		strcpy(infile_name, DEFAULT_IN_FILE1);
        }

	/* Read the file into a text buffer */
	if ((in_fp = fopen(infile_name, "r")) == NULL) {
		fprintf(stderr, "Can not open %s\n", infile_name);
		exit(0);
	}

	in_fd = fileno(in_fp);
	fstat(in_fd, &stat_buf);
	filesize = stat_buf.st_size;

	text_string = (char *)XtMalloc(filesize + 1);
	bytes_read = fread(text_string, sizeof(char ), filesize, in_fp);
	if (bytes_read != filesize) {
		printf("filesize = %d bytes_read = %d\n", filesize, bytes_read);
		fclose(in_fp);
		exit(0);
	}
	*(text_string + filesize) = '\0';

	rewind(in_fp);
	while (fgets(line, MAX_LINE_LEN, in_fp) != NULL)
		total_lines++;

	fclose(in_fp);

}

#define WORD_LEN    32

ProcessCommandArgs()
{

    char    *user_data;
    char    next_word[WORD_LEN + 1];
    int     num_spaces;

    user_data = UserData;

    while (*user_data != '\0') {

        get_next_word(user_data, next_word, &num_spaces);
        user_data += (strlen(next_word) + num_spaces);

        if (strcmp(next_word, "-f") == 0) {

        	get_next_word(user_data, next_word, &num_spaces);
        	user_data += (strlen(next_word) + num_spaces);
			strcpy(infile_name, next_word);
            continue;

        }
		if (strcmp(next_word, "-use_word_wrap") == 0) {
			word_wrap_on = True;
			continue;
		}
		if (strcmp(next_word, "-test_word_wrap_on") == 0) {
			test_word_wrap = True;
			word_wrap_on = True;
			continue;
		}
		if (strcmp(next_word, "-test_word_wrap_off") == 0) {
			test_word_wrap = True;
			word_wrap_on = False;
			continue;
		}
		if (strcmp(next_word, "-show_perf_bug") == 0) {
			show_perf_bug = True;
			continue;
		}

    }

    free(UserData);

}


get_next_word(source, dest, spaces)
char    *source;
char    *dest;
int     *spaces;
{

    int n;
    int space_count;

    space_count = 0;

    while (isspace(*source)) {
        source++;
        space_count++;
    }

    n = 0;
    while (!isspace(*source) && *source != '\0' && n < WORD_LEN) {
        *dest++ = *source++;
        n++;
    }
    *dest = '\0';
    *spaces = space_count;

}
