/* 
 * Motif
 *
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these librararies and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
*/ 
/* 
 * HISTORY
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$TOG: main.c /main/8 1997/03/31 13:54:57 dbl $"
#endif
#endif

#include "main.h"

/* ===============================================================
 *   The Done Callback. Set the locale to the selected one
 *	in the radio box
 */

static void DoneCallback(Widget button,
			 XtPointer client_data, XtPointer call_data)

{
   ViewPtr this = (ViewPtr) client_data;
   Widget b;

   XtVaGetValues(locale_box, XmNmenuHistory, &b, NULL);
   XtVaGetValues(b, XmNuserData, &SelectedLocale, NULL);
   LocaleName = LocaleTable[CurrentOS][SelectedLocale];
   printf ("language selected\n");
}

/* ===============================================================
 *    Create a dialog box to verify the OS and choose the locale
 */
static Widget CreateLocaleBox(ViewPtr this, OS os, String os_name)
{
   Widget select_box, pick_form;
   Widget framed[2], frame;
   Widget languages[MaxLanguage+1] ;
   Widget oss[MaxOS+1] ;
   int i, lang;
   Arg args[20];
   int count; 
   int n;
   Widget os_panel;
   Widget lang_frame, os_frame;
   char s[255];
   int def_lang = 0;
   XmString msg, msg1, msg2;

   n = 0;
   XtSetArg(args[n], XmNmessageString,
	    XmStringCreateSimple("Select a language, Verify your OS"));
   n++;
   XtSetArg(args[n], XmNokLabelString, XmStringCreateSimple("Done"));
   n++;
   select_box = XmCreateTemplateDialog(theWidgetRoot, "search_box", args, n);
   XtAddCallback(select_box,
		 XmNokCallback, (XtCallbackProc) DoneCallback,
		 (XtPointer) this);
   n = 0;
   pick_form = XmCreateForm(select_box, "form", args, n);
   n = 0;
   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; 
   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM) ; n++;
   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM) ; n++;
   lang_frame = XmCreateFrame(pick_form, "lang_frame", args, n);
   n = 0;
   XtSetArg(args[n], XmNframeChildType, XmFRAME_TITLE_CHILD); n++;
   XtSetArg(args[n], XmNlabelString, XmStringCreateSimple("Language")); n++;
   framed[0] = XmCreateLabel(lang_frame, "title", args, n);
   n = 0;
   XtSetArg(args[n], XmNframeChildType, XmFRAME_WORKAREA_CHILD); n++;
   XtSetArg(args[n], XmNisAligned, True); n++;
   XtSetArg(args[n], XmNradioAlwaysOne, True); n++;
   XtSetArg(args[n], XmNentryAlignment, XmALIGNMENT_END); n++;
   XtSetArg(args[n], XmNentryClass, xmToggleButtonWidgetClass); n++;
   XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
   framed[1] = XmCreateRadioBox(lang_frame, "lang_box", args, n);
   locale_box = framed[1];
   def_lang = 0;
   for (count= 0, i = 0; i < MaxLanguage ; i++) {
      if (SupportedLocale [os][i]) {
	 if (i == French)
	   def_lang = French;
	 n = 0;
	 XtSetArg(args[n], XmNlabelString, 
		  XmStringCreateSimple(LangList[i])); n++;
	 XtSetArg(args[n], XmNuserData, i); n++;
	 languages[count] = 
	   XmCreateToggleButton(framed[1], LangList[i], args, n);
	 ++count;
      }
      else printf("%s does not support %s\n", OSList[os], LangList[i]);
   }
   XtManageChildren(languages, count);
   XtManageChildren(framed, 2);
   XtManageChild(lang_frame);
   XmToggleButtonSetState(languages[def_lang], True, True);

   n = 0;
   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; 
   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; 
   XtSetArg(args[n], XmNtopWidget, lang_frame); n++; 
   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM) ; n++;
   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM) ; n++;
   if (os < MaxOS) 
     { 
	sprintf(s, "Your Operating System is %s", os_name);
	msg = XmStringCreateSimple(s);
	XtSetArg(args[n], XmNlabelString, msg); n++;
	os_frame = XmCreateLabel(pick_form, "title", args, n);
     }

   else {
      os_frame = XmCreateFrame(pick_form, "os_frame", args, n);
      n = 0;
      XtSetArg(args[n], XmNframeChildType, XmFRAME_TITLE_CHILD); n++;
      XtSetArg(args[n], 
	       XmNlabelString, XmStringCreateSimple("Operating System"));
      n++;
      framed[0] = XmCreateLabel(os_frame, "title", args, n);
      n = 0;
      XtSetArg(args[n], XmNframeChildType, XmFRAME_WORKAREA_CHILD); n++;
      XtSetArg(args[n], XmNisAligned, True); n++;
      XtSetArg(args[n], XmNradioAlwaysOne, True); n++;
      XtSetArg(args[n], XmNentryAlignment, XmALIGNMENT_END); n++;
      XtSetArg(args[n], XmNentryClass, xmToggleButtonWidgetClass); n++;
      XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
      framed[1] =
	os_box = XmCreateRadioBox(os_frame, "os_box", args, n);
      n = 0;
      XtSetArg(args[n], XmNlabelString, 
	       XmStringCreateSimple(OSList[i])); n++;
      for (i = 0; i < MaxOS ; i++) {
	 n = 0;
	 XtSetArg(args[n], XmNuserData, i); n++;
	 XtSetArg(args[n], XmNlabelString, 
		  XmStringCreateSimple(OSList[i])); n++;
	 oss[i] = XmCreateToggleButton(framed[1], OSList[i], args, n);
      }
      n = 0;
      XtSetArg(args[n], XmNuserData, MaxOS); n++;
      XtSetArg(args[n], XmNlabelString, 
	       XmStringCreateSimple("Other"));
      n++;
      oss[MaxOS] = XmCreateToggleButton(framed[1],
					OSList[i], args, n);
      XtManageChildren(oss, MaxOS+1);
      XtManageChildren(framed, 2);
      XmToggleButtonSetState(oss[MaxOS-1], True, True);
   }
   XtManageChild(os_frame);
   XtManageChild(pick_form);
   return select_box;
}

/* ===============================================================
 *    Create a dialog box to verify the OS and choose the locale
 */
static void SelectLocale(ViewPtr this, OS os, String os_name)
{
   Widget select_box;
   
   if (locale_box == NULL)
     select_box = CreateLocaleBox(this, os, os_name);
   XtManageChild(select_box);

}

/* ===============================================================
 *    Main: Initialize, create the application shell and loop
 * Check that the language specified is 
 * supported by fileview and libX and libC.
 */
int main(int argc, char *argv[])
{
#define C_locale_name "C"
   char **p1, **p2;
   int i;
   ViewPtr this;
   XEvent event;
   String new_locale;
   char msg[128];
   String lang = getenv("LANG");
   OS os;
   struct utsname os_def;
   char filename[255];
   Language l;

/* 
 * init widget names
 */
   new_pane = "new_pane";
   kill_pane = "kill_pane";
   search = "search";

   /* save argc and argv */
   save_argc = argc;
   save_argv = (char **) XtCalloc(argc, sizeof(char *));
   for ( p1 = argv, p2 = save_argv, i = argc; i-- > 0 ; ) 
     *p2++ = *p1++ ;
   /* alloc the object for the primary view */
   this = (ViewPtr) XtCalloc(sizeof(View), 1);

   XtToolkitInitialize();
   MrmInitialize();
   theContext = XtCreateApplicationContext();

   uname(&os_def);
   for (os = 0; os < MaxOS ; os++)
     if (strcmp(os_def.sysname, OSList[os]) == 0)
	 break;
   CurrentOS = os;
   for (l = 1;  l < MaxLanguage; l++) {
      if (setlocale(LC_ALL, LocaleTable[os][l]) == NULL 
	  ||  ! XSupportsLocale()) {
	 sprintf(msg, "Locale `%s' not supported by C and/or X library", 
		 LocaleTable[os][l]);
	 XtAppWarning(theContext, msg);
	 SupportedLocale [CurrentOS][SelectedLocale] = False;
      }
   }
   setlocale(LC_ALL, "C");
   theDisplay = XtOpenDisplay(theContext, NULL, myName, myClass, 
			      NULL, 0, &argc, argv);
   
   theWidgetRoot = XtAppCreateShell(myName, myClass,
				    applicationShellWidgetClass,
				    theDisplay, NULL, 0);
   
   XtGetApplicationResources(theWidgetRoot, &FileViewResources,
			     FileViewResourcesSpecs, 
			     XtNumber(FileViewResourcesSpecs),
			     (ArgList) NULL, 0);
   
   do {
      SelectLocale(this, os, os_def.sysname);
      do {
	 XtAppNextEvent(theContext, &event);
	 XtDispatchEvent(&event);
      } while (LocaleName == NULL);
      new_locale = setlocale(LC_ALL, LocaleName); 
      if (new_locale == NULL ||  ! XSupportsLocale() )
	{
	   SupportedLocale [CurrentOS][SelectedLocale] = False;
	   new_locale = NULL; 
	}
      else if (! XSetLocaleModifiers(""))
	XtAppWarning(theContext,
		     "X locale modifiers not supported, using default");
      
   } while ( new_locale == NULL);

   XtDestroyWidget(theWidgetRoot);
   XtCloseDisplay(theDisplay);
   XtSetLanguageProc(theContext, (XtLanguageProc) MyLanguageProc, theContext); 
   theDisplay = XtOpenDisplay(theContext, NULL, myName, myClass, 
			      NULL, 0, &argc, argv);

   theWidgetRoot = XtAppCreateShell(myName, myClass,
				    applicationShellWidgetClass,
				    theDisplay, NULL, 0);


   if (strcmp(FileViewResources.version, "NoValue") == 0) {
      Screen * screen = XtScreenOfObject(theWidgetRoot);
      XrmDatabase db = XtScreenDatabase(screen);

      strcpy(filename, LangList[SelectedLocale]);
      strcat(filename, ".df");
      printf("default %s\n", filename);
      XrmCombineFileDatabase(filename, &db, True);
   }
   strcpy(filename, LangList[SelectedLocale]);
   strcat(filename, ".uid");
   uid_files[0] = filename;
   if (MrmOpenHierarchyPerDisplay(theDisplay, 1, uid_files,
				   NULL, &theUIDdatabase)
        != MrmSUCCESS)
       /* || (MrmRegisterNames(regvec, regnum) != MrmSUCCESS)) */
     {
        fprintf (stderr,
                 "Cannot open hierarchy defined by %s\n", uid_files[0]);
     }

   NewFileShell(theWidgetRoot, this, save_argc, save_argv);
   XtPopup(this->shell, XtGrabNone);
   /* XtRealizeWidget(this->text_source); */
   XtAppMainLoop(theContext);
   
   return 0;    /* make compiler happy */
}

/* ===============================================================
 * The language proc.
 * Note: Xt guarantees that xnl is not NULL. No need to test it.
 * Return a language string usable by XtResolvePathname.
 */
static String MyLanguageProc(Display * dpy, String xnl, 
			     XtAppContext theContext)
{
   return setlocale(LC_CTYPE, NULL);
}

/* ===============================================================
 *   Create a new top level shell.
 * 	If primary is true create a quit entry,
 *	else a close entryn
 */
static ViewPtr NewFileShell(Widget parent, ViewPtr this,
			   int argc, char *argv[])
{
   Widget mw, children[4], menubar, entry;
   Arg args[20];
   String names[8];
   XtCallbackProc procs[8];
   XtPointer private[8];
   int n;
   Dimension width, height;
   WidgetClass class;
   Bool primary = True;

#define SetMenuEntry(k,l,p,d) names[k]=l;procs[k]=p;private[k]=d;

   n = 0;
   XtSetArg(args[n], XmNallowShellResize, True); n++;
   if (this == NULL) {
      this = (ViewPtr) XtCalloc(sizeof(View), 1);
      XtSetArg(args[n], XmNtitle, "File" ); n++;
      class = topLevelShellWidgetClass;
   }
   else {
      XtSetArg(args[n], XmNargv, argv); n++;
      XtSetArg(args[n], XmNargc, argc); n++;
      XtSetArg(args[n], XmNtitle, "File View Main"); n++;
      class = applicationShellWidgetClass;
   }
   this->shell = XtCreatePopupShell("primary", class, parent, args, n);
/*
 * Create the main window, the menubar and the pane 
 * Store the view in userData for further use.
 */
   n = 0;
   XtSetArg(args[n], XmNuserData, this); n++;
   mw = XmCreateMainWindow(this->shell, "main", args, n);
   children[0] = XmCreateMenuBar(mw, "menubar", NULL, 0);

   n = 0;
   SetMenuEntry(n, "open", (XtCallbackProc) OpenFileCallback,
		(XtPointer) this); n++;
   SetMenuEntry(n, "opennew", (XtCallbackProc) OpenNewShellCallback,
		(XtPointer) this); n++;
   SetMenuEntry(n, NULL, NULL, NULL); n++;
   if (primary) {
      SetMenuEntry(n, "exit",  (XtCallbackProc) ExitCallback,
		   (XtPointer) parent);
   }
   else {
      SetMenuEntry(n, "close",  (XtCallbackProc) CloseCallback,
		   (XtPointer) this);
   }
   n++;

   (void) CreateMenuBarEntry(children[0], "file", names, procs, private, n);
   
   n = 0;
   SetMenuEntry(n, new_pane, (XtCallbackProc) NewPaneCallback,
		(XtPointer) this); n++;
   SetMenuEntry(n, kill_pane,(XtCallbackProc) KillPaneCallback,
		(XtPointer) this); n++;
   SetMenuEntry(n, search, (XtCallbackProc) FindCallback,
		(XtPointer) this); n++;
   this->view_cascade = 
     CreateMenuBarEntry(children[0], "view", names, procs, private, n);
   SetSensitive(this->view_cascade, new_pane, False);
   SetSensitive(this->view_cascade, kill_pane, False);
   SetSensitive(this->view_cascade, search, False);
   
   SetMenuEntry(0, "help_view", (XtCallbackProc) HelpCallback,
		(XtPointer) this);
   entry = CreateMenuBarEntry(children[0], "help", names, procs, private, 1);

   n = 0;
   XtSetArg(args[n], XmNmenuHelpWidget, entry); n++;
   XtSetValues(children[0], args, n);
   XtManageChild(children[0]);

   n = 0;
   width = WidthOfScreen(XtScreenOfObject(mw)) / 2 ;
   height = HeightOfScreen(XtScreenOfObject(mw)) * 2 / 3 ;
   XtSetArg(args[n], XmNwidth, width); n++;
   XtSetArg(args[n], XmNheight, height); n++;
   XtSetArg(args[n], XmNresizePolicy, XmRESIZE_NONE); n++;
   children[1] = XmCreateForm(mw, "work", args, n);

   n = 0;
   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; 
   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; 
   XtSetArg(args[n], XmNrightAttachment,  XmATTACH_FORM) ; n++;
   XtSetArg(args[n], XmNleftAttachment,  XmATTACH_FORM) ; n++;
   this->paned_window = XmCreatePanedWindow(children[1], "panes", args, n);
   XtManageChild(this->paned_window);
   n = 0;
   this->text_source = XmCreateText(children[1],   /* the form */
				    "textsource", args, n);
   n = 0;
   this->path = children[2] = XmCreateLabel(mw, "filename", args, n);

   n = 0;
   XtSetArg(args[n], XmNmenuBar, children[0]); n++;
   XtSetArg(args[n], XmNworkWindow, children[1]); n++;
   XtSetArg(args[n], XmNmessageWindow, children[2]); n++;
   XtSetValues(mw, args, n);
   XtManageChildren(children, 3);
   XtManageChild(mw);
   return this;
}

/* ===============================================================
 *   Create a cascade and a pulldown entry into a menubar, 
 * 	from a list of push button specs.
 *   If the label is NULL, create a separator instead of a push button.
 */
static Widget CreateMenuBarEntry(Widget menubar, String entry, String names[],
				 XtCallbackProc procs[],
				 XtPointer private[], int count)
{
   Widget menu;
   Widget child;
   Arg args[8];
   int n;
   int i;
   char menu_name[64];

   n = 0;
   XtSetArg(args[n], XmNtearOffModel, XmTEAR_OFF_ENABLED); n++;
   menu = XmCreatePulldownMenu(menubar, 
			       strcat(strcpy(menu_name, entry), "Menu"),
			       args, n);
   for(i = 0; i < count; i++) {
      n = 0;
      if (names[i] == NULL)
	child = XmCreateSeparator(menu, "sep", args, n);
      else {
	 child = XmCreatePushButton(menu, names[i], args, n);
	 if (procs[i] != NULL)
	   XtAddCallback(child, XmNactivateCallback, procs[i], private[i]);
      }
      XtManageChild(child);
   }
   n = 0;
   XtSetArg(args[n], XmNsubMenuId, menu); n++;
   child = XmCreateCascadeButton(menubar, entry, args, n);
   XtManageChild(child);
   return child;
}

/* ===============================================================
 *   Routine to change menu bar items sensitivity.
 *   Takes a cascade button, extract the pulldown, find the item.
 */

void SetSensitive(Widget cascade, String item, Boolean sensitive)
{
   Widget menu, button;

   XtVaGetValues(cascade, XmNsubMenuId, &menu, NULL);
   button = XtNameToWidget(menu, item);
   XtSetSensitive(button, sensitive);
}

/* ===============================================================
 *   The Exit Callback. The root widget is passed as client data.
 *	Close properly. Exit.
 */

static void ExitCallback(Widget button, Widget root,
			 XmPushButtonCallbackStruct *call_data)
{
   Display * dpy = XtDisplay(root);

   XtDestroyWidget(root);
   XtCloseDisplay(dpy);
   exit(0);
}

/* ===============================================================
 *   The Close Callback. The root widget is passed as client data.
 *	Close properly. Exit.
 */

static void CloseCallback(Widget button, ViewPtr this,
			  XmPushButtonCallbackStruct *call_data)
{

   printf("close callback\n");
   XtDestroyWidget(this->shell);
   XtFree((char *) this);
}

/* ===================================================================
 * The Help callback: Show an information message box.
 */
static void HelpCallback(Widget	widget, ViewPtr this,
			 XmPushButtonCallbackStruct *call_data)
{
  static Widget HelpDialog = NULL;

  if ( HelpDialog == NULL ) {
     Arg args[8];
     int n = 0;
     XmString help1, help2, help3, help_msg;
     
     help1 = XmStringConcatAndFree(FetchString(this, "help_file"),
				   XmStringSeparatorCreate());
     help2 = XmStringConcatAndFree(FetchString(this, "help_view"),
				   XmStringSeparatorCreate());
     help_msg = XmStringConcatAndFree(XmStringConcatAndFree(help1, help2), 
				      FetchString(this, "help_search"));

     XtSetArg(args[n], XmNmessageString, help_msg); 
     n++;
     HelpDialog = XmCreateInformationDialog(this->shell,
					    "helpdialog", args, n);
     XmStringFree(help_msg);
  }
  XtManageChild(HelpDialog);
}

/* ===============================================================
 *   The Open New Shell Callback. 
 * The primary View object is passed in the client_data
 *	Open a new shell and a new file selected by a file selection box.
 */

static void OpenNewShellCallback(Widget widget, ViewPtr this,
			 XmPushButtonCallbackStruct *call_data)
{
   XmPushButtonCallbackStruct dummy_data;
   ViewPtr view;

   view = NewFileShell(theWidgetRoot, NULL, 0, NULL);
   XtPopup(view->shell, XtGrabNone); 
}

/* ===============================================================
 *   The Open File Callback. The View object is passed in the client_data
 *	Open a new file selected by a file selection box.
 */

static void OpenFileCallback(Widget widget, ViewPtr this,
			 XmPushButtonCallbackStruct *call_data)
{
   Arg args[8];
   int n = 0;

   if (this->fsb == NULL) {
      this->fsb = CreateFileSelectionBox(this);
      XtManageChild(this->fsb);
   }
   else if (XtIsManaged(this->fsb))
     XtPopup(XtParent(this->fsb), XtGrabNone);
   else XtManageChild(this->fsb);
}

/* ===============================================================
 *   Create File Selection Box
 */
static Widget CreateFileSelectionBox(ViewPtr this)
{
   Arg args[8];
   int n = 0;
   Widget fsb;
   
   XtSetArg(args[n], XmNallowShellResize, True); n++;
   XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW);  n++;
/*
     XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL);
     n++;
 */
   fsb = XmCreateFileSelectionDialog(this->shell, "fsb", args, n);
   XtAddCallback(fsb, XmNokCallback, (XtCallbackProc) FileOKCallback, this);
   XtAddCallback(fsb, XmNcancelCallback, (XtCallbackProc) FileCancelCallback,
		 this);
   return fsb;
}

/* ===================================================================
 * Pop down the fsb.
 */
static void FileCancelCallback(Widget fsb, ViewPtr this,
			XmFileSelectionBoxCallbackStruct *call_data)
{
   XtPopdown(XtParent(this->fsb));
}

/* =====================================================================
 * Fetch an string from Mrm database
 */

XmString FetchString(ViewPtr this, String name)
{
   MrmCode code;
   XmString fetched;

   if (MrmFetchLiteral(theUIDdatabase, name, theDisplay,
		       (XtPointer) &fetched, (MrmCode *) &code) == MrmSUCCESS) 
     return fetched;

   ViewError(this, XmStringCreateLocalized("Can't fetch from database: "),
		  XmStringCreateLocalized(name));
   return XmStringCreateLocalized("String Not Found");
}

/* =====================================================================
 * Show application modal error dialogue box
 */

void ViewError(ViewPtr this, XmString s1, XmString s2)
{
   XmString msg;

   msg = XmStringConcatAndFree(s1, s2);

   if (this->error_box == NULL) {
      Arg args[8];
      int n = 0;

      XtSetArg(args[n], XmNdialogStyle, 
	       XmDIALOG_FULL_APPLICATION_MODAL);
      n++;
      this->error_box = XmCreateErrorDialog(this->shell, "error", args, n);
   }
   XtVaSetValues(this->error_box, XmNmessageString, msg, NULL);
   XtManageChild(this->error_box);
   XmStringFree(msg);
}

/* =====================================================================
 * Show application modal error dialogue box
 */

void ViewWarning(ViewPtr this, XmString s1, XmString s2)
{
   XmString msg;

   msg = XmStringConcatAndFree(s1, s2);

   if (this->warning_box == NULL) {
      Arg args[8];
      int n = 0;

      XtSetArg(args[n], XmNdialogStyle, 
	       XmDIALOG_FULL_APPLICATION_MODAL);
      n++;
      this->warning_box = XmCreateWarningDialog(this->shell, 
						"warning", args, n);
   }
   XtVaSetValues(this->warning_box, XmNmessageString, msg, NULL);
   XtManageChild(this->warning_box);
   XmStringFree(msg);
}
