#include <stdio.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/cursorfont.h>

#include <X11/Xaw/Form.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Viewport.h>

#include <sys/types.h>
#include <sys/time.h>
#include <time.h>

#include "moviedb.h"
#include "filmography.h"
#include "dbutils.h"

#include "LinkView.h"
#include "PcBar.h"
#include "LinkText.h"
#include "xregal.h"
#include "searchname.h"
#include "searchtitle.h"
#include "file.h"
#include "lookupname.h"
#include "lookuptitle.h"
#include "cname.h"
#include "popup.h"
#include "history.h"
#include "actions.h"
#include "genre.h"
#include "keyword.h"
#include "find.h"
#include "filmbuf.h"



/* Global variables that all files need to access. */

char errorbuf[256];
XtAppContext app_context;
Boolean search_in_progress=False;
char *imdbsite;


/* fallback resources */

static String fallback_resources[] = {
	"*Command.shapeStyle: oval",
	"*MenuButton.shapeStyle: oval",
	"*viewer.font1: -adobe-times-medium-r-normal--*-140-*-*-p-*-iso8859-1",
	"*viewer.font2: -adobe-times-medium-i-normal--*-140-*-*-p-*-iso8859-1",
	"*viewer.font3: -adobe-helvetica-bold-r-normal-*-*-180-*-*-p-*-iso8859-1",
	"*viewer.font4: -adobe-helvetica-bold-r-normal--*-140-*-*-p-*-iso8859-1",
	"*viewer.font5: -adobe-times-bold-i-normal--*-140-*-*-p-*-iso8859-1",
	"*viewer.color1: black",
	"*viewer.color2: black",
	"*viewer.color3: black",
	"*viewer.color4: black",
	"*pcbar.height: 4",
	"*pcbar.foreground: darkorange3",
	"*mainmenubutton.leftBitmap: dropbar8",
	"*searchmenubutton.leftBitmap: dropbar8",
	"*aboutbox.form.message.font:            -*-times-medium-*-*-*-*-140-*-*-*-*-*-*",
	"*Alert.form.message.font:            -*-times-medium-r-*-*-*-180-*-*-*-*-*-*",
	"*LinkView.useBottom: true",
	"*LinkView.useRight: true",
	"*vport.childResizable: true",
	"*mainmenubutton.width:  65",
	"*mainmenubutton.cursor: hand2",
	"*searchmenubutton.width:  65",
	"*url_label.font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*",
	"*url_text*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*",
    "*vport.translations:    #override\\n"
    "   <Key>q:          byebye()\\n"
    "   Alt<Key>x:       byebye()\\n"
    "   <Key>b:          goback()\\n"
    "   <Key>F3:         findtext()\\n"
    "   <Key>f:          goforward()\\n"
    "   <Key>g:          searchgenre()\\n"
    "   <Key>k:          searchkeyword()\\n"
    "   <Key>h:          history()\\n"
    "   <Key>s:          savetofile()\\n"
    "   <Key>c:          searchcname()\\n"
    "   <Key>n:          searchname()\\n"
    "   <Key>t:          searchtitle()",
	"*Command.cursor: hand2",
	"*topform*Command.width: 65",
	"*h_form*Command.width: 65",
	"*genre_view.height: 350",
	"*genre_list.forceColumns: true",
	"*genre_list.defaultColumns: 2",
	"*genre_label.justification: center",
	"*genremenubutton.shapeStyle: rectangle",
    "*keyword_view.height: 350",
    "*keyword_list.forceColumns: true",
    "*keyword_list.defaultColumns: 2",
    "*keyword_list.verticalList: true",
    "*keyword_label.justification: center",
    "*keywordmenubutton.shapeStyle: rectangle",

	/* Labels */

	"*find_shell.title: Find a string",
	"*find_label.label: Search for",
	"*genre_shell.title: Genre Search",
    "*keyword_shell.title: Keyword Search",
    "*keyword_label.label: Show categories with at least",
	"*fs_shell.title: Save to file",
	"*ts_shell.title: Movie Title Search",
	"*tse_label.label: Movie title:",
	"*ns_shell.title: Name Search",
	"*nse_label.label: Person's name:",
	"*cs_shell.title: Character Name Search",
	"*cse_label.label: Character name:",
	"*forwardbutton.label: Forward",
	"*backbutton.label: Back",
	"*historybutton.label: History",
	"*url_label.label: URL:",
	"*mainmenubutton.label: Main",
	"*searchmenubutton.label: Search",
	NULL
};

AppData app_data;
static XtResource resources[] = {
	{"showprogress","Showprogress",XtRBoolean,sizeof(Boolean),
		XtOffset(AppDataPtr, showprogress),XtRImmediate, (XtPointer) True},
#ifdef CRASHME
	{"crashme","Crashme",XtRInt,sizeof(int),
		XtOffset(AppDataPtr, crashme),XtRImmediate, (XtPointer) 0},
#endif
	{"casttab","Casttab",XtRInt,sizeof(int),
		XtOffset(AppDataPtr, casttab),XtRImmediate, (XtPointer) 200},
	{"chartab","Chartab",XtRInt,sizeof(int),
		XtOffset(AppDataPtr, chartab),XtRImmediate, (XtPointer) 0},
	{"techtab","Techtab",XtRInt,sizeof(int),
		XtOffset(AppDataPtr, techtab),XtRImmediate, (XtPointer) 120},
	{"quotetab","Quotetab",XtRInt,sizeof(int),
		XtOffset(AppDataPtr, quotetab),XtRImmediate, (XtPointer) 50},
	{"hangingIndent","HangingIndent",XtRInt,sizeof(int),
		XtOffset(AppDataPtr, hangingIndent),XtRImmediate, (XtPointer) 40},
	{"substringMax","SubstringMax",XtRInt,sizeof(int),
		XtOffset(AppDataPtr, substringMax),XtRImmediate, (XtPointer) 500},
	{"popupPosition","PopupPosition",XtRString,sizeof(String),
		XtOffset(AppDataPtr, popupPosition),XtRString, (XtPointer) NULL},
	{"historyMax","HistoryMax",XtRInt,sizeof(int),
		XtOffset(AppDataPtr, historyMax),XtRImmediate, (XtPointer) 25},
	{"alphaSort","AlphaSort",XtRBoolean,sizeof(Boolean),
		XtOffset(AppDataPtr, alphaSort),XtRImmediate, (XtPointer) False},
#ifdef NAME_COMPLETION
	{"nameCompletion","NameCompletion",XtRString,sizeof(XtPointer),
		XtOffset(AppDataPtr, nameCompletion),XtRImmediate, (XtPointer) "whenNeeded"},
#endif
	{"laserDisc","LaserDisc",XtRBoolean,sizeof(Boolean),
		XtOffset(AppDataPtr, laserDisc),XtRImmediate, (XtPointer) True},
	{"imdbSite","ImdbSite",XtRString,sizeof(String),
		XtOffset(AppDataPtr, imdbSite),XtRString, (XtPointer) NULL},
    {"keywordInitial","KeywordInitial",XtRInt,sizeof(int),
            XtOffset(AppDataPtr, keywordInitial),XtRImmediate, (XtPointer) 3},
	};

static XrmOptionDescRec options[] =
{
    {"-nopcbar", ".showprogress", XrmoptionNoArg, "False"},
    {"-laserDisc", ".laserDisc", XrmoptionSepArg, NULL},
#ifdef NAME_COMPLETION
    {"-completion", ".nameCompletion", XrmoptionSepArg, NULL},
#endif
    {"-crashme", ".crashme", XrmoptionSepArg, NULL},
    {"-casttab", ".casttab", XrmoptionSepArg, NULL},
    {"-chartab", ".chartab", XrmoptionSepArg, NULL},
    {"-techtab", ".techtab", XrmoptionSepArg, NULL},
    {"-quotetab", ".quotetab", XrmoptionSepArg, NULL},
    {"-hangingIndent", ".hangingIndent", XrmoptionSepArg, NULL},
    {"-substringMax", ".substringMax", XrmoptionSepArg, NULL},
    {"-historyMax", ".historyMax", XrmoptionSepArg, NULL},
    {"-alpha", ".alphaSort", XrmoptionNoArg, "True"},
    {"-imdbSite", ".imdbSite", XrmoptionSepArg, NULL},
};

Widget 	topLevel, 
		topform,
		mainmenu, 
		mainmenubutton,
		searchmenu, 
		searchmenubutton,
		title,
		pcbar,
		vport,
		viewer,
		aboutbox,
		backbutton,
		forwardbutton,
		historybutton,
		url_label,
		url_text;

char *main_menu_item[] = {
	"Save to file",
	"About",
	"Exit"
	};
#define MAIN_MENU_ITEMS 3

char *search_menu_item[] = {
	"Search for Movie",
	"Search for Name",
	"Search for Character Name",
	"Search for Genre",
    "Search for Keyword",
	"Find ...",
	};

#define SEARCH_MENU_ITEMS 6

Widget main_menu_widget[MAIN_MENU_ITEMS];
Widget search_menu_widget[SEARCH_MENU_ITEMS];

char about_text[] = 
        "xregal " VERNUM"\n\n"
        VERDATE"\n\n"
        "by\n\n"
        "Lachlan Wetherall\n\n"
        "e-mail: Lachlan.Wetherall@compsys.com.au\n"
		"www: http://users.hunterlink.net.au/~dglw\n";

char COPYRIGHT[80];

Cursor busyCursor = (Cursor) 0;
Cursor unBusyCursor = (Cursor) 0;


void PopDownAbout(Widget w, XtPointer closure, XtPointer call_data) {
        XtPopdown((Widget) closure);
        XtDestroyWidget((Widget) closure);
        }

void PopUpAbout(void) {
    aboutbox=MessageBox(topLevel, "aboutbox", about_text, "OK", PopDownAbout, NULL);
    SetPopup(topLevel, aboutbox);
    XStoreName(XtDisplay(topLevel), XtWindow(aboutbox), "About");
    }

void enableSearch(void) {
	XtVaSetValues(searchmenubutton, XtNsensitive, True, NULL);
	}

void disableSearch(void) {
	XtVaSetValues(searchmenubutton, XtNsensitive, False, NULL);
	}

static void SearchMenu(Widget w, XtPointer client_data, XtPointer garbage) {
	int item = (int) client_data;

	switch (item) {
		case 0:
			PopupSearchTitle();
			break;
		case 1:
			PopupSearchName();
			break;
		case 2:
			PopupSearchCharacterName();
			break;
		case 3:
			PopupGenre();
			break;
		case 4:
            PopupKeyword();
            break;
        case 5:
			PopupFind();
			break;
		default:
			XtAppWarning(app_context, "SearchMenu option not implemented.");
			break;
		}
	}

static void MainMenu(Widget w, XtPointer client_data, XtPointer garbage) {
	int item = (int) client_data;

	switch (item) {
		case 0:
			PopupFileSave();
			break;
		case 1:
			PopUpAbout();
			break;
		case 2:
			exit(0);
		default:
			XtAppWarning(app_context, "MainMenu option not implemented.");
			break;
		}
	}


static char titlebuf[256];

void SetTitle(char *str) {
	strcpy(titlebuf, str);
	XtVaSetValues(title, XtNlabel, titlebuf, NULL);
	}


void new_page(Widget w, XtPointer client_data, XtPointer call_data) {
	PageRecord *p = (PageRecord*) call_data;
	char buf[256];

	if (p->total <= 1)
		return;

	sprintf(buf, "%s (Page %d of %d)", titlebuf, p->current+1, p->total);
	XtVaSetValues(title, XtNlabel, buf, NULL);
	}



void link_pressed(Widget w, XtPointer client_data, XtPointer call_data) {
	LinkRecord *c = (LinkRecord*) call_data;
	int n, i;
	int lists[NO_OF_FILMOGRAPHY_LISTS];
	char namebuf[256];
	Boolean found;
	Boolean trytitle=False;
	char *cp;

	/* printf("%s\n", c->link); */

	/* if a search is in progress, do nothing */
	if (search_in_progress)
		return;

	if (sscanf(c->link, "%d:", &n)==1) {
		strcpy(namebuf, strchr(c->link, ':')+1);
		/* for the moment, we'll look up every list */
		for (i=0; i<NO_OF_FILMOGRAPHY_LISTS; i++)
			lists[i]=1;
		found=LookupName(namebuf, lists, True, SEARCH_EXACT);
		if (found) 
			return;

		/* if not found, possibly due to a (qv) reference to a name
			that occurs multiple times in the database - try a less
			stringent search */
		found=LookupName(namebuf, lists, False, SEARCH_EXACT);
		if (found) 
			return;


		/* if not found, possibly due to 'Movie Title' (qv) instead of
		   _Movie Title_ (qv) -  therefore try searching for a movie title */
		trytitle=True;
		}

	if ((strncmp(c->link, "MOV", 3)==0) || trytitle) {
		cp=strchr(c->link,':');
		if (cp!=NULL)
			strcpy(namebuf, cp+1);
		else
			strcpy(namebuf, c->text);
		found=LookupTitle(namebuf, SEARCH_EXACT, False);
		if (!found) {
			Alert("Invalid link or no matching data.\n(Possibly due to an  incorrect database entry.)");
			XBell(XtDisplay(topLevel), 100);
			}
		}
	else {
		Alert("Error: Malformed link.");
		XBell(XtDisplay(topLevel), 100);
		}
	}


int main(int argc, char *argv[]) {
	int i;
	char *cl_title=NULL;
	char *cl_name=NULL;
	Boolean found;
	int lists[NO_OF_FILMOGRAPHY_LISTS];
	Dimension baselineskip;
	int maxlines;
	char buf[256];
    time_t ti;
    struct tm *clock;
	int year;
	extern void filmographyResultsTitleKeyLookup(struct nameSearchRec *chain);

	topLevel = XtVaAppInitialize(&app_context,"XRegal",
		(XrmOptionDescList) options, (Cardinal) XtNumber(options),
		&argc,argv,fallback_resources, NULL);

    /* Get application resources */
    XtVaGetApplicationResources(topLevel, &app_data, resources, XtNumber(resources), NULL);

	/* check out command line options */
	i=1;
	while (i<argc) {
		if (strcmp(argv[i], "-movie")==0) {
			if (++i==argc) 
				XtAppError(app_context, "You must supply a search string with the '-movie' option!");
			cl_title=argv[i];
			}
		else if (strcmp(argv[i], "-person")==0) {
			if (++i==argc) 
				XtAppError(app_context, "You must supply a search string with the '-person' option!");
			cl_name=argv[i];
			}
		else  {
			sprintf(errorbuf, "Invalid command line option: %s", argv[i]);
			XtAppError(app_context, errorbuf);
			}
		i++;
		}
	if ((cl_title!=NULL) && (cl_name!=NULL)) 
		XtAppError(app_context, "You cannot specify both '-movie' and '-person'.");


	/* This seemingly pointless piece of code has a purpose - if the database
       files are inaccessible (missing, in wrong place, wrong file protections),
       then the user finds out when xregal starts - not after they've gone to 
       the trouble of typing in a query. (Program will exit if file is not
       accessible.) */

	filmographyResultsTitleKeyLookup(NULL);

	/* Work out which IMDB web site to reference. */
	if (app_data.imdbSite != NULL)
		imdbsite = app_data.imdbSite;
	else
		imdbsite = IMDBSITE;     /* defined in xregal.h or Imakefile */

	/* initialise the copyright message */

    ti=time(NULL);
    clock=localtime(&ti);
	year = clock->tm_year+1900;
	if (year<COPYRIGHT_END_YEAR)
		year = COPYRIGHT_END_YEAR;
	sprintf(COPYRIGHT, COPYRIGHT_TEMPLATE, year);

	/* Create widgets in main window */
	topform = XtVaCreateManagedWidget("topform", formWidgetClass, topLevel, NULL);
	mainmenubutton = XtVaCreateManagedWidget("mainmenubutton", menuButtonWidgetClass, topform, 
        XtNmenuName, "mainmenu",
		XtNbottom, XtChainTop,
		XtNleft, XtChainLeft,
		XtNright, XtChainLeft,
		NULL);
	searchmenubutton = XtVaCreateManagedWidget("searchmenubutton", menuButtonWidgetClass, topform, 
        XtNmenuName, "searchmenu",
		XtNfromHoriz, mainmenubutton,
		XtNbottom, XtChainTop,
		XtNleft, XtChainLeft,
		XtNright, XtChainLeft,
		NULL);

	if (app_data.historyMax>0) {
		backbutton = XtVaCreateManagedWidget("backbutton", commandWidgetClass, topform,
			XtNsensitive, False,
			XtNfromHoriz, searchmenubutton,
			XtNbottom, XtChainTop,
			XtNleft, XtChainLeft,
			XtNright,XtChainLeft,
			NULL);
		XtAddCallback(backbutton, XtNcallback, backCB, NULL);
		forwardbutton = XtVaCreateManagedWidget("forwardbutton", commandWidgetClass, topform,
			XtNsensitive, False,
			XtNfromHoriz, backbutton,
			XtNbottom, XtChainTop,
			XtNleft, XtChainLeft,
			XtNright,XtChainLeft,
			NULL);
		XtAddCallback(forwardbutton, XtNcallback, forwardCB, NULL);
		historybutton = XtVaCreateManagedWidget("historybutton", commandWidgetClass, topform,
			XtNsensitive, False,
			XtNfromHoriz, forwardbutton,
			XtNbottom, XtChainTop,
			XtNleft, XtChainLeft,
			XtNright,XtChainLeft,
			NULL);
		XtAddCallback(historybutton, XtNcallback, historyCB, NULL);
		CreateHistoryDialog();
		}

	title = XtVaCreateManagedWidget("title", labelWidgetClass, topform,
		XtNfromVert, mainmenubutton,
		XtNlabel, "",
        XtNwidth, 500, 
        XtNborderWidth, 0,
		XtNtop, XtChainTop,
		XtNbottom, XtChainTop,
		NULL);
	pcbar = XtVaCreateManagedWidget("pcbar", pcBarWidgetClass, topform,
		XtNfromVert, title,
        XtNwidth, 500, 
        XtNborderWidth, 0,
		XtNtop, XtChainTop,
		XtNbottom, XtChainTop,
		XtNleft, XtChainLeft,
		XtNright, XtChainRight,
		XtNvertDistance, 0,
		NULL);
	vport = XtVaCreateManagedWidget("vport", linkViewWidgetClass, topform,
        XtNheight, 500,
        XtNwidth, 500, 
		XtNfromVert, pcbar,
        XtNallowHoriz, True,
        XtNallowVert, True,                                     
		XtNbottom, XtChainBottom,
		XtNtop, XtChainTop,
		XtNleft, XtChainLeft,
		XtNright, XtChainRight,
        NULL);
	viewer = XtVaCreateManagedWidget("viewer", linkTextWidgetClass, vport, NULL);
	XtAddCallback(viewer, XtNactivate, link_pressed, 0);
	XtAddCallback(viewer, XtNnewpage, new_page, 0);

	url_label = XtVaCreateManagedWidget("url_label", labelWidgetClass, topform,
		XtNfromVert, vport,
        XtNwidth, 40, 
        XtNborderWidth, 0,
		XtNleft, XtChainLeft,
		XtNright, XtChainLeft,
		XtNtop, XtChainBottom,
		XtNbottom, XtChainBottom,
		NULL);
	url_text = XtVaCreateManagedWidget("url_text", asciiTextWidgetClass, topform,
		XtNfromVert, vport,
		XtNfromHoriz, url_label,
        XtNwidth, 460, 
        XtNborderWidth, 0,
		XtNleft, XtChainLeft,
		XtNright, XtChainRight,
		XtNtop, XtChainBottom,
		XtNbottom, XtChainBottom,
		XtNdisplayCaret, False,
		NULL);
	mainmenu = XtVaCreatePopupShell("mainmenu",simpleMenuWidgetClass,mainmenubutton,
        XtNborderWidth, 2,
        NULL);
	searchmenu = XtVaCreatePopupShell("searchmenu",simpleMenuWidgetClass, searchmenubutton,
        XtNborderWidth, 2,
        NULL);

    for (i=0; i<MAIN_MENU_ITEMS; i++) {
        String item = main_menu_item[i];
        main_menu_widget[i] = XtVaCreateManagedWidget(item, smeBSBObjectClass, mainmenu, 
                XtNjustify, XtJustifyLeft,
                XtNlabel, item,
                NULL);

        XtAddCallback(main_menu_widget[i], XtNcallback, MainMenu, (XtPointer) i);
        }
    for (i=0; i<SEARCH_MENU_ITEMS; i++) {
        String item = search_menu_item[i];
        search_menu_widget[i] = XtVaCreateManagedWidget(item, smeBSBObjectClass, searchmenu, 
                XtNjustify, XtJustifyLeft,
                XtNlabel, item,
                NULL);

        XtAddCallback(search_menu_widget[i], XtNcallback, SearchMenu, (XtPointer) i);
        }

	
	/* Create dialog boxes */

	CreateNameSearchDialog();
	CreateCharacterNameSearchDialog();
	CreateFindDialog();
	CreateTitleSearchDialog();
	CreateFileSaveDialog();

	XtAppAddActions(app_context, xregal_actions, xregal_actions_num);

	/* Create cursors */
	busyCursor = XCreateFontCursor(XtDisplay(topLevel), XC_watch);
    unBusyCursor = XCreateFontCursor(XtDisplay(topLevel), XC_left_ptr);

	/* tell the scrolling viewer how high lines of text are */
	baselineskip=GetBaselineskip(viewer);
	XtVaSetValues(vport, XtNbaselineskip, baselineskip, NULL);

	/* make sure that substringMax is not set too high */
	maxlines=32767/baselineskip -100;
	if (app_data.substringMax>maxlines) {
		sprintf(errorbuf, "With current font settings the maximum value of substringMax is %d.\n", maxlines);
		XtAppWarning(app_context, errorbuf);
		app_data.substringMax=maxlines;
		}
	XtRealizeWidget(topLevel);

#ifdef CRASHME
	if (app_data.crashme>0) 
		crashme();
	else if (app_data.crashme<0) 
		crashme_name();
#endif

	if (cl_title!=NULL) {
		found=LookupTitle(cl_title, SEARCH_EXACT, False);
        if (!found) {
			Alert("No matches found!");
			XBell(XtDisplay(topLevel), 100);
			}
		}
	else if (cl_name!=NULL) {
		/* for the moment, we'll look up every list */
		for (i=0; i<NO_OF_FILMOGRAPHY_LISTS; i++)
			lists[i]=1;
		found=LookupName(cl_name, lists, False, SEARCH_EXACT);
        if (!found) {
			Alert("No matches found!");
			XBell(XtDisplay(topLevel), 100);
			}
		}

	sprintf(buf, "xregal %s", VERNUM);
	XStoreName(XtDisplay(topLevel), XtWindow(topLevel), buf);

/*	ClearFilmbuf();
	for (i=0; i<5000; i++) {
		sprintf(buf, "This is line %d\n", i);
		AddToFilmbuf(buf);
		}
    XtVaSetValues(viewer, XtNhypertext, Filmbuf(), NULL);*/

	XtAppMainLoop(app_context);


	return(1);
} /* End main */
