
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <locale.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xmu/Error.h>
#include <X11/Xatom.h>
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <Xm/Xm.h>
#include <Xm/Protocols.h>
#include <Xm/Form.h>
#include <Xm/ScrolledW.h>
#include <Xm/DrawingA.h>
#include <wchar.h>   /* prototypes for wide character routines  28SEP98RCJ */
#include "XmHTML.h"  /* added 25JUN98RCJ for XmHTML HTML Widget 25JUN98RCJ */

XtAppContext app_context;
Display *display;       /*  Display             */
Widget  toplevel;
static  Widget  topDrawArea    = (Widget)NULL;
static  Widget  bottomDrawArea = (Widget)NULL;
static  XmFontList fontlist = (XmFontList)NULL;
static  XFontSet font_set = (XFontSet)NULL;
static  long total = (long)0;

static char *testString = (char *)NULL;
static wchar_t *wc_array = (wchar_t *)NULL;
static char *defaultString = 
  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890";
static XFontStruct *testFontStruct = (XFontStruct *)NULL;
static char *testFont = (char *)NULL;
static char *defaultFont = 
   "-dt-interface system-medium-r-normal-s sans-14-140-72-72-p-82-iso8859-1";

Pixel   steelBluePixel = (Pixel) NULL;
Pixel   redpixel    = (Pixel) NULL;
Pixel   yellowpixel = (Pixel) NULL;
Pixel   greenpixel  = (Pixel) NULL;
Pixel   orangepixel = (Pixel) NULL;
Pixel   whitepixel  = (Pixel) NULL;
Pixel   blackpixel  = (Pixel) NULL;

GC topDrawGC=(GC)NULL;
GC bottomDrawGC=(GC)NULL;

#if 0
static void GiveUp(int signo);
#endif

static void AllocateColors(Widget w)
{
    Colormap cmap = (Colormap)NULL;
    XColor   new_color,unused;

       if (yellowpixel) return;  /* if this pixel set, assume colors allocated */

       XtVaGetValues(w, XmNcolormap,&cmap,NULL);
       if ( !cmap ) return;

       XAllocNamedColor(XtDisplay(w),cmap,
                        "white", &new_color,&unused);

       whitepixel = new_color.pixel;

       XAllocNamedColor(XtDisplay(w),cmap,
                        "red", &new_color,&unused);

       redpixel = new_color.pixel;

       XAllocNamedColor(XtDisplay(w),cmap,
                        "black", &new_color,&unused);

       blackpixel = new_color.pixel;

       if (
       XAllocNamedColor(XtDisplay(w),cmap,
                        "SteelBlue", &new_color,&unused))
         steelBluePixel = new_color.pixel;
       else {
            printf("Could not allocate background color SteelBlue. Using black instead\n");
            steelBluePixel = blackpixel;
       }

       XAllocNamedColor(XtDisplay(w),cmap,
                        "yellow", &new_color,&unused);

       yellowpixel = new_color.pixel;

       XAllocNamedColor(XtDisplay(w),cmap,
                        "orange", &new_color,&unused);

       orangepixel = new_color.pixel;

       XAllocNamedColor(XtDisplay(w),cmap,
                        "green", &new_color,&unused);

       greenpixel = new_color.pixel;
}

static void GiveUp(int signo)
{
    printf("GiveUp Entered...\n");

    exit(0); /* terminate */
    return;
}

static void KillWindow(Widget w, XtPointer client_data, XtPointer call_data)
{
    GiveUp((int)0);
    return;
}

static int catcher (Display *dpy, XErrorEvent *err)
{
    if (err->request_code != X_GetAtomName) {
        XmuPrintDefaultErrorMessage (dpy, err, stderr);
    }
    return 0;
}

char *GetFontFamily(char *fontname, char **charset)
{
    char *foundry  = (char *)NULL;
    char *family   = (char *)NULL;
    char *start    = (char *)NULL;
    char *encoding = (char *)NULL;
    char *width    = (char *)NULL;
    char *spacing  = (char *)NULL;
    char *ptr;
    char *result = (char *)NULL;
    char fontfamily[512];
    char **names = (char **)NULL;
    int  i,dashs=5;

    *charset=(char *)NULL;  /* so far no character set */

    /********************************************************************/
    /*  Create the character set encoding from the passed font name     */
    /********************************************************************/

    if (fontname && *fontname) {            /* if passed a font name */
       encoding=ptr=strdup(fontname);       /* get a copy to modify  */
       dashs = 13;                          /* locate 13th dash      */

        while (*ptr && dashs) {             /* skip to spacing field */
           while (*ptr && *ptr!='-') ptr++; /* find next dash        */
           if (*ptr) {                      /* if not string end     */
              dashs--;                      /* count dash if got 1   */
              ptr++;                        /* skip over dash        */
           }
        }

        if (*ptr && *ptr!='*') { /* if 13th dash found and not wild carded */
           *charset = strdup(ptr);           /* get char encoding     */
        } else *charset=strdup("iso8859-1"); /* else use default      */

        if (encoding) free(encoding);
        encoding = (char *)NULL;
    }  else *charset=strdup("iso8859-1");    /* else use default      */

    /********************************************************************/
    /*  Create the font family name from the passed font name           */
    /********************************************************************/
    if (fontname && *fontname) {           /* if passed a font name */
        start=ptr=strdup(fontname);        /* get a copy to modify  */

        while (*ptr && *ptr=='-') ptr++;   /* find foundry name     */
        if (*ptr) foundry=ptr;             /* foundry name          */
        while (*ptr && *ptr!='-') ptr++;   /* skip over remainder   */
        if (*ptr) *ptr++='\0';             /* terminate foundry     */

        if (*ptr) family=ptr;              /* family name start     */
        while (*ptr && *ptr!='-') ptr++;   /* skip over remainder   */
        if (*ptr) *ptr++='\0';             /* terminate family      */

        while (*ptr && *ptr!='-') ptr++;   /* skip over weight      */
        if (*ptr) ptr++;                   /* skip over dash        */

        while (*ptr && *ptr!='-') ptr++;   /* skip over slant       */
        if (*ptr) ptr++;                   /* skip over dash        */

        if (*ptr) width=ptr;               /* font width start      */
        while (*ptr && *ptr!='-') ptr++;   /* skip over remainder   */
        if (*ptr) *ptr++='\0';             /* terminate font width  */

        dashs=5;                            /* 5 dashs to spacing    */
        while (*ptr && dashs) {             /* skip to spacing field */
           while (*ptr && *ptr!='-') ptr++; /* find next dash        */
           if (*ptr) {                      /* if not string end     */
              dashs--;                      /* count dash if got 1   */
              ptr++;                        /* skip over dash        */
           }
        }

        if (*ptr) spacing=ptr;              /* spacing spacing       */
        while (*ptr && *ptr!='-') ptr++;    /* skip over remainder   */
        if (*ptr) *ptr='\0';                /* terminate spacing     */

        if (foundry && family && width &&
            spacing) sprintf (fontfamily,"%s-%s-%s-%s",foundry,family,
                                                       width,spacing);
        else strcpy(fontfamily,"adobe-times-normal-*");

    } else strcpy(fontfamily,"adobe-times-normal-*");

    result=strdup(fontfamily);
    return(result);
}

void DumpFontInfo(char *fontname, XFontStruct *info)
{
    int i;
    int  count;
    char *atomname;
    char *propname;
    int  direction;
    int  ascent,descent;
    XCharStruct char_info;
    int (*oldhandler)(Display *dpy, XErrorEvent *err) = XSetErrorHandler (catcher);

    if (!fontname) {
       printf("NULL font name passed to DumpFontInfo. Exiting.\n");
       return;
    }

    if (!info) {
       printf("NULL XFontStruct pointer passed to DumpFontInfo. Exiting.\n");
       return;
    }

    XQueryTextExtents(XtDisplay(toplevel),info->fid,"M",(int)1,&direction,
                      &ascent,&descent,&char_info);
    printf("\n\nXFontStruct Information for font:\n\n%s:\n\n",fontname);

    printf("ascent(M)........................%d\n",ascent);
    printf("descent(M).......................%d\n",descent);
    printf("width(M).........................%d\n",char_info.width);
    printf("attributes(M)..................0x%x\n",char_info.attributes);
    printf("info->max_bounds->lbearing.......%d\n",info->max_bounds.lbearing);
    printf("info->max_bounds->rbearing.......%d\n",info->max_bounds.rbearing);
    printf("info->max_bounds->width..........%d\n",info->max_bounds.width);
    printf("info->max_bounds->ascent.........%d\n",info->max_bounds.ascent);
    printf("info->max_bounds->descent........%d\n",info->max_bounds.descent);
    printf("info->max_bounds->attributes.....%d\n\n",info->max_bounds.attributes);
    
    count=1;
    while ((atomname = XGetAtomName(XtDisplay(toplevel),count++))) {
       XFree(atomname);
       atomname = (char *)NULL;
    }

    XSetErrorHandler (oldhandler);

    printf("Number of Properties=%d\n",info->n_properties);

    if (info->n_properties) {
        for (i=0;i<info->n_properties;i++) {

#if 0
             printf("i=%d name Atom=%d prop Atom=%d\n",i,
                     (unsigned long)info->properties[i].name,
                     (unsigned long)info->properties[i].card32);
#endif

             atomname = (char *)NULL;
             if (info->properties[i].name > 0 && 
                 info->properties[i].name < count)
                 atomname = XGetAtomName(XtDisplay(toplevel),info->properties[i].name);

             propname = (char *)NULL;
             if (info->properties[i].card32 > 0 && 
                 info->properties[i].card32 < count)
                 propname = XGetAtomName(XtDisplay(toplevel),
                                        (Atom)info->properties[i].card32);
             if (atomname) {
                if (propname) {
                    printf(
                    "Property %3d AtomName=%u=%s PropName=(unsigned decimal)%u=%s\n",
                     i,(unsigned long)info->properties[i].name,
                     atomname,(unsigned long)info->properties[i].card32,
                     propname);
                     XFree(propname);
                 } else {
                    printf(
                    "Property %3d AtomName=%u=%s PropName=(unsigned decimal)%u (unknown)\n",
                     i,(unsigned long)info->properties[i].name,
                     atomname,(unsigned long)info->properties[i].card32);
                 }
                 XFree(atomname);
             } else {
                if (propname) {
                    printf(
                    "Property %3d AtomName=%u=(unknown) PropName=%u=%s\n",
                     i,(unsigned long)info->properties[i].name,
                     (unsigned long)info->properties[i].card32,
                     propname);
                     XFree(propname);
                } else {
                    printf(
                    "Property %3d AtomName=%u=(unknown) PropName=(unsigned decimal)%u=(unknown)\n",
                     i,(unsigned long)info->properties[i].name,
                       (unsigned long)info->properties[i].card32);
                }
             }
        }
    }
}

void drawAreaExpose_CB(Widget widget, XtPointer client_data, XtPointer call_data )
{
    XmDrawingAreaCallbackStruct *cbs = 
      (XmDrawingAreaCallbackStruct *) call_data;
    int    baseX;        /* X coordinate of string baseline.     */
    int    baseY;        /* Y coordinate of string baseline.     */
    char   **fontpath;
    int    n,i,j,paths;
    Status error = (Status)NULL;
    Colormap cmap = (Colormap)NULL;
    XColor exact_def, screen_def;
    GC *drawAreaGC=(GC *)NULL;
    Dimension tall=0;
    wchar_t wc,temp;
    unsigned char *mb_string=(unsigned char *)NULL;
    unsigned int bite;
    int      bytes;
    unsigned char *actual;
    unsigned char *uptr;
    unsigned char *mbptr=(unsigned char *)NULL;
    wchar_t *ptr   = (wchar_t *)NULL;
    wchar_t *start = (wchar_t *)NULL;
    wchar_t *begin = (wchar_t *)NULL;
    wchar_t *wcptr = (wchar_t *)NULL;
    int   bites = 0;
    int   mbs = 0;
    XmString  sample;
    size_t  status;
    static XFontStruct *defaultInfo = (XFontStruct *)NULL;
    static XGCValues gcv;
    static debug=0;

    printf("drawAreaExpose_CB entered...\n");
    if (widget == topDrawArea) drawAreaGC = &topDrawGC;
    else                       drawAreaGC = &bottomDrawGC;

    if (!*drawAreaGC ) {
        gcv.foreground = whitepixel;
        gcv.background = steelBluePixel;
        *drawAreaGC = XCreateGC (XtDisplay(widget),
                        RootWindowOfScreen(XtScreen(widget)),
                        (GCForeground | GCBackground), &gcv);
        if (*drawAreaGC) {
            paths = 0;
            fontpath = (char **)NULL;
            fontpath = XGetFontPath(XtDisplay(widget),&paths);

            if (fontpath && paths > 0) {
                printf("\nCurrent Font Path is:\n\n");
                for (i=0;i<paths;i++) {
                   printf("%s\n",fontpath[i]);
                }
                printf("\n");
                XFreeFontPath(fontpath);
            }

            if ((testFontStruct = XLoadQueryFont(XtDisplay(widget),
                                                testFont)) == NULL) {
                printf(
                "drawAreaExpose_CB. XLoadQueryFont of small font Failed.\n");
            } else {
                DumpFontInfo(testFont,testFontStruct);
            }

        } else {
                printf(
                "drawAreaExpose_CB. XCreateGC Failed.\n");
                return;        
        }
        XSetFunction(XtDisplay(widget), *drawAreaGC, GXcopy); /* do straight copy */
    }

    baseX=baseY=25;

    if (testFontStruct && testString) {
        if (testFontStruct->fid) {
            XSetFont(XtDisplay(widget),*drawAreaGC,testFontStruct->fid);
            start = ptr = (wchar_t *)malloc((total*sizeof(wchar_t)));
            wcscpy(start,wc_array);
            temp = *ptr;
            while (temp) {  /* while all strings in buffer not output */
                wcptr = begin = ptr;          /* save this line start        */
                while (*ptr && *ptr !='\n') { /* while end of line not found */
                   ptr++;                     /* bump to next character      */
                }
                temp = *ptr;                  /* save in case its buffer end */
                *ptr = '\0';                  /* replace new line with NULL  */
                ptr++;                        /* bump past string end        */

                if (!tall) { /* get line height in pixels just once */
                    sample =    XmStringCreate(defaultString,"TAG1");
                    tall   =    XmStringHeight(fontlist,sample);
                    if (sample) XmStringFree(sample);
                }

                bites = wcslen(begin);       /* get wide character byte string length */
                
                mb_string = (unsigned char *)malloc((bites*sizeof(wchar_t)));
                status = wcstombs((char *)mb_string,begin,(bites*sizeof(wchar_t)));
                mbptr = mb_string;

                bytes = 0;
                n = mblen((char *)mbptr,(size_t)bites);
                while ( n > 0 ) {
                    bytes = bytes + n;
                    mbptr = mbptr + n;
                    n     = mblen((char *)mbptr,(size_t)bites);
                }

                if (mb_string) {
                    XmbDrawString(XtDisplay(toplevel),XtWindow(widget),font_set,
                                  *drawAreaGC,baseX,baseY,(char *)mb_string,bytes);
                    free(mb_string);
                }
                
                baseY += tall;
            }
        }
        if (start) free(start);
    }
    
    XtVaGetValues(widget, XmNcolormap,&cmap,NULL);
    error=XLookupColor(XtDisplay(widget),cmap,"blue",&exact_def,&screen_def);
}

#if 0
int main (int argc, char **argv)/

main(argc, argv)
    int argc;
    char **argv;
#endif

main(
    int argc,
    char *argv[] )
{
    Widget main_form,top_form,bottom_form;
    Widget scrolledw;
    Widget _htmlWidget;
    Atom   WM_DELETE_WINDOW;
    long   eof;
    int    infd;
    int    i,j;
    XmFontListEntry entry1 = (XmFontListEntry)NULL;
    char   *locale=(char *)NULL;
    wchar_t wc;
    wchar_t *wc_ptr;
    size_t  status;
    char **miss_charsets=(char **)NULL;
    int  miss_count=0;
    char *def_string=(char *)NULL;
    char *fontfamily = (char *)NULL;
    char *charset    = (char *)NULL;

        locale = setlocale(LC_ALL,"");        /* get the local locale */

        testFont   = defaultFont;
        testString = defaultString;
        total      = strlen(testString);     /* get length test string */

        if (argc > 1) testFont   = argv[1];
        if (argc == 3) { /* 2nd arg is name of a text file to render */
               infd=open(argv[2],O_RDONLY);

               if (infd <=0 ) { /* if we could not open the file */ 
                   printf(
                   "Could not open file %s. Exiting...\n",argv[2]);
                   exit(1);
               }

               eof=lseek(infd,0L,2);           /* seek to end to get file length */
               total=lseek(infd,0L,0);         /* move back to file beginning    */
               testString=(char *)malloc(((eof+4)/4)*4); /* get file size buffer */
               total=read(infd,testString,eof);          /* read entire file     */
               testString[eof]='\0';                     /* terminate string     */
               close(infd);                              /* close the file       */
        } else if ( argc > 3 ) {
             printf(
             "Syntax error. Too many arguments. Proper Syntax is:\n\n");
             printf("htmltest [XLFD Font Name] [HTML file name]\n\n");
             exit(0);
        }

        XtSetLanguageProc ( (XtAppContext) NULL, (XtLanguageProc) NULL, (XtPointer) NULL );

        toplevel = XtVaAppInitialize(&app_context, "SampleApp", NULL, 0, 
                                     &argc, argv,
                                     NULL,
                                     XmNtitle,
                                     "Test Program for XmHTML HTML Render Widget",
                                     NULL);

        if (testFont) {
            entry1 = XmFontListEntryLoad(XtDisplay(toplevel),testFont,
                                         XmFONT_IS_FONT,"TAG1");
            if (entry1) {
                fontlist = XmFontListAppendEntry(NULL, entry1);
                XmFontListEntryFree(&entry1);
            }
        }

        if (!testFont || !entry1 || !fontlist) {
            printf(
            "Error. Unable to create font entry for font. Exiting...\n");
            exit(2);
        }

        font_set = XCreateFontSet(XtDisplay(toplevel),testFont,&miss_charsets,
                                  &miss_count,&def_string);

        if (miss_count > 0 ) {
            printf("\nWARNING: Missing charsets for font %s\nreturned from XCreateFontSet.\n\n",
                   testFont); 
            printf("Missing charsets are:\n");

            for (i=0;i<miss_count;i++) {
                printf("%s\n",miss_charsets[i]);
            }
            printf("\nText may not render correctly due to missing charsets...\n\n");
        }

        if (!font_set) {
            printf("\nFATAL ERROR: Could not create font set for font:\n");
            printf("%s\n",testFont);
            printf("Exiting...\n\n");
            exit(3);
       }

        if ( total > 0 ) {
             wc_ptr = wc_array = (wchar_t *)malloc((total*sizeof(wchar_t)));
             status   = mbstowcs(wc_array, testString, total);
             wc       = *wc_ptr++;
             while(wc) {
                wc = *wc_ptr;
                wc_ptr++;
             }
        } else {
        }

        main_form = XtVaCreateWidget("main_form",xmFormWidgetClass,toplevel,
                                      XmNfractionBase,       100,
                                      XmNwidth,  (Dimension) 600,
                                      XmNheight, (Dimension) 700,
                                      XtVaTypedArg,XmNforeground,XmRString,"white",6,
                                      XtVaTypedArg,XmNbackground,XmRString,"SteelBlue",10,
                                      NULL);

        AllocateColors  (main_form);

        top_form = XtVaCreateWidget("main_form",xmFormWidgetClass,main_form,
                                      XmNtopAttachment,    XmATTACH_FORM,
                                      XmNleftAttachment,   XmATTACH_FORM,
                                      XmNrightAttachment,  XmATTACH_FORM,
                                      XmNbottomAttachment, XmATTACH_POSITION,
                                      XmNbottomPosition,   50, /* 50% */
                                      XtVaTypedArg,XmNforeground,XmRString,"white",6,
                                      XtVaTypedArg,XmNbackground,XmRString,"SteelBlue",10,
                                      NULL);

        bottom_form = XtVaCreateWidget("main_form",xmFormWidgetClass,main_form,
                                      XmNtopAttachment,    XmATTACH_WIDGET,
                                      XmNtopWidget,        top_form,
                                      XmNleftAttachment,   XmATTACH_FORM,
                                      XmNrightAttachment,  XmATTACH_FORM,
                                      XmNbottomAttachment, XmATTACH_FORM,
                                      XtVaTypedArg,XmNforeground,XmRString,"white",6,
                                      XtVaTypedArg,XmNbackground,XmRString,"SteelBlue",10,
                                      NULL);

        topDrawArea = XtVaCreateWidget("drawTopArea",xmDrawingAreaWidgetClass,top_form,
                                      XmNtopAttachment,    XmATTACH_FORM,
                                      XmNbottomAttachment, XmATTACH_FORM,
                                      XmNleftAttachment,   XmATTACH_FORM,
                                      XmNrightAttachment,  XmATTACH_FORM,
                                      XmNbackground,       steelBluePixel,
                                      NULL);

        scrolledw = XtVaCreateWidget("scrolledHTML",
                        xmScrolledWindowWidgetClass, bottom_form,
                        XmNtopAttachment,    XmATTACH_FORM,
                        XmNrightAttachment,  XmATTACH_FORM,
                        XmNleftAttachment,   XmATTACH_FORM,
                        XmNbottomAttachment, XmATTACH_FORM,
                        NULL);

        fontfamily = GetFontFamily(testFont, &charset);

        if (!fontfamily) {
           printf("FATAL ERROR.  Unable to create font family string from font:\n\n");
           printf("%s\n\n",testFont);
           printf("Exiting....\n");
           exit(4);
        }

        _htmlWidget = XtVaCreateWidget("html",
                        xmHTMLWidgetClass,   scrolledw,
                        XmNbackground,       steelBluePixel,
                        XmNfontFamily,       fontfamily,
                        XmNcharset,          charset,
#if 0 /** let this default 21SEP98RCJ **/
                        XmNfontFamily,      "sun-song-normal-*",
                        XmNfontSizeList,    fontsizes,
                        XmNfontFamily,      fixedfamily,
                        XmNfontFamilyFixed, fixedfamily,
#endif
                        NULL);

        XtAddCallback(topDrawArea, XmNexposeCallback, drawAreaExpose_CB,
                      (XtPointer)NULL);

        XtVaSetValues(toplevel,XmNdeleteResponse,XmDO_NOTHING,NULL);
        WM_DELETE_WINDOW = XmInternAtom(XtDisplay(toplevel),"WM_DELETE_WINDOW",
                                        False);
        XmAddWMProtocolCallback(toplevel,WM_DELETE_WINDOW,
                                KillWindow,(XtPointer) NULL);

        XmHTMLTextSetString(_htmlWidget, testString);
        XmHTMLTextScrollToLine(_htmlWidget, 0);

        XtManageChild   (_htmlWidget);
        XtManageChild   (scrolledw);
        XtManageChild   (topDrawArea);
        XtManageChild   (top_form);
        XtManageChild   (bottom_form);
        XtManageChild   (main_form);
        XtRealizeWidget (toplevel);

        XtAppMainLoop(app_context);
} /* end main */

