/* Mtinkc.c
 * Copyright (C) 2001 Jean-Jacques Sarton jj.sarton@t-online.de
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/* This file look for the configurations file ~/mtinkrc[.*] and
   present a choice for the case you have more mptinters
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <ctype.h>

#include <Xm/Xm.h>
#include <Xm/MwmUtil.h>
#include <Xm/Display.h>
#include <X11/Core.h>
#include <X11/Shell.h>
#include <Xm/PanedW.h>
#include <Xm/MainW.h>
#include <Xm/Form.h>
#include <Xm/ScrollBar.h>
#include <Xm/ScrolledW.h>
#include <Xm/List.h>
#include <Xm/Separator.h>
#include <Xm/RowColumn.h>
#include <Xm/TextF.h>

#include <Xm/PushB.h>
#include <Xm/Label.h>
#include <Xm/Frame.h>
#include <Xm/MwmUtil.h>

#define COMMAND "mtink -c %d %s &"

char *fallbackResources[] =
{
  /*! an other grey */
  "*background: #cccccc",
  "! for Motif 1.2/Lesstif make look as for openMotif",
  "*TopShadowColor: #eeeeee",
  "*BottomShadowColor: #111111",

  "*foreground: black",
  "*shadowThickness: 1",
  "*XmSeparator.shadowThickness: 2",
  "*visibleItemCount: 4",
  "*XmList.background: white",
  "*XmList.foreground: darkblue",
  "*XmList.highlightThickness: 0",

  /* default resources */
  "*dialogTitle: Mtink Chooser",
  "*title_LB.labelString: Mtink: Printer Selection",
  "*ok_PB.labelString: OK",
  "*cancel_PB.labelString: Cancel",
  "*new: Add new printer",

  /* german resources */
  "*De*dialogTitle: Mtink Auswahl",
  "*De*title_LB.labelString: Mtink: Drucker Auswahl",
  "*De*ok_PB.labelString: OK",
  "*De*cancel_PB.labelString: Abbruch",
  "*De.new: Drucker hinzufügen",

  /* french resources */
  "*Fr*dialogTitle: Mtink Choix",
  "*Fr*title_LB.labelString: Mtink: Choix imprimante",
  "*Fr*ok_PB.labelString: OK",
  "*Fr*cancel_PB.labelString: Annuller",
  "*Fr.new: Nouvelle imprimante",

  /* danish resources */
  "*Da*dialogTitle: Mtink Vćlger",
  "*Da*title_LB.labelString: Mtink: Vćlg printer",
  "*Da*ok_PB.labelString: OK",
  "*Da*cancel_PB.labelString: Afbryd",
  "*Da.new: Tilfřj ny printer",


 /* hungarian resources */
  "*Hu*dialogTitle: Mtink választó",
  "*Hu*title_LB.labelString: Mtink: Nyomtató kijelölés",
  "*Hu*ok_PB.labelString: OK",
  "*Hu*cancel_PB.labelString: Visszavon",
  "*Hu*new: Új nyomtató hozzáadása",
   NULL
};

/* list of hosts and comments which will be displayed */

typedef struct nodes_s
{
   int   confNr;
   char *printer;
} nodes_t;

nodes_t *nodes;

/* prototypes */

static Widget createLayout(char *language);
static int readRc(char *prgName, nodes_t **nodes);
static void fillList(Widget list, int n, nodes_t *);
static void callCommand(int pos, Widget w);
static char *skipSpace(char*s);
static void cancel_CB(Widget w, XtPointer clientData, XtPointer callData);
static void ok_CB(Widget w, XtPointer clientData, XtPointer callData);

char  guiLanguage[20];
char *prgName;
char *mainResource;
char *dispString = NULL;

Widget topLevel;
Widget mainWindow;
Widget mainForm;
Widget title_LB;
Widget node_LST;
Widget cancel_PB;
Widget ok_PB;
XtAppContext  theApp;

/*******************************************************************/
/* Function cmpInt(char *s)                                        */
/*                                                                 */
/* compare the confNr for sorting                                  */
/*                                                                 */
/*******************************************************************/

int cmpInt(const void *P1, const void *P2)
{
   nodes_t *p1 = (nodes_t *)P1;
   nodes_t *p2 = (nodes_t *)P2;
   return p1->confNr - p2->confNr;
}

/*******************************************************************/
/* Function skipSpace(char *s)                                     */
/*                                                                 */
/* advance pointer up to the next non space character              */
/*                                                                 */
/*******************************************************************/

static char *skipSpace(char*s)
{
   while(*s && (*s==' '||*s=='\t') )
      s++;
   return s;
}

/*******************************************************************/
/* Function readRC(char *prgName, nodes_t **nodes)                 */
/*                                                                 */
/* Read the file .<prgName> in the home directory and allocate     */
/* and fill the *node structure with the conten of the file.       */
/*                                                                 */
/* Lines begining with [ }*# are sikped, the same apply with lines */
/* without content.                                                */
/* the first word is the name of the remote host. the rest are     */
/* comments which will be displayed.                               */
/*                                                                 */
/* return the number of lines with informations                    */
/*                                                                 */
/*******************************************************************/

int readRc(char *prgName, nodes_t **nodes)
{
   char          *home = getenv("HOME");
   char          *fileName;
   FILE          *fp;
   char          *s;
   int            len = 0;
   char           buf[1024];
   int            i   = 0;
   char           search[] = "PRINTER:";
   int            slen = strlen(search);
   DIR           *dir;
   struct dirent *ent;

   fileName = (char*)calloc(strlen(home)+100,1);

   *nodes = (nodes_t*)calloc(sizeof(nodes_t),1);
   
   if ( (dir = opendir(home)) )
   {
      while ( (ent = readdir(dir)) != NULL )
      {
         if ( strncmp(ent->d_name, ".mtinkrc", 8 ) )
         {
            continue;
         }
         if ( ent->d_name[8] == '\0' )
            i = 0;
         else if ( ent->d_name[8] == '.' )
            i = atoi(&ent->d_name[9]);
         else
            continue;

         if ( i )
            sprintf(fileName,"%s/.mtinkrc.%d",home,i);
         else
            sprintf(fileName,"%s/.mtinkrc",home);
         if ( (fp = fopen(fileName,"r")) )
         {
            while(fgets(buf, sizeof(buf), fp) )
            {
               s = buf;
               while(*s && *s != '\n' ) s++;
               *s = '\0';

               if ( (s = strchr(buf, '\0')) )
                  *s = '\0';
               s = skipSpace(buf);
               if ( strncmp(search,s, slen) )
               {
                  continue;
               }
               else
               {
                  s += slen;
 
                  *nodes = (nodes_t*)realloc(*nodes,sizeof(nodes_t)*(len+2));
                  s = skipSpace(s);
                  if ( *s )
                  {
                     (*nodes)[len].printer=strdup(s);
                     (*nodes)[len].confNr=i;;
                     len++;
                     (*nodes)[len].printer = 0;
                     (*nodes)[len].confNr  = 0;
                  }
               }
            }
            fclose(fp);
         }
      }
      closedir(dir);
   }
   free(fileName);
   return len;
}

/*******************************************************************/
/* Function cancel_CB()                                            */
/*                                                                 */
/* The user don't like us, terminate.                              */
/*                                                                 */
/*******************************************************************/

void cancel_CB(Widget w, XtPointer clientData, XtPointer callData)
{
   exit(0);
}

/*******************************************************************/
/* Function callCommand(int pos, Widget w)                         */
/*                                                                 */
/* Call mtink.                                                     */
/*                                                                 */
/*******************************************************************/

void callCommand(int pos, Widget w)
{
   char command[1024];
      
   sprintf(command,COMMAND,
           nodes[pos].confNr, dispString);

   system(command);
}

/*******************************************************************/
/* Function ok_CB()                                                */
/*                                                                 */
/* The user want to start mtink                                    */
/*                                                                 */
/*******************************************************************/

void ok_CB(Widget w, XtPointer clientData, XtPointer callData)
{
   int  pos = 0;
   int *position_list;
   int  position_count;
   
   /* look for the selected host */
   XmListGetSelectedPos(node_LST, &position_list, &position_count );

   if ( position_count > 0)
   {
      pos = position_list[0]-1;
   }
   else
   {
      /* #@!*, nothings is selected */
      XBell(XtDisplay(w),100);
      return;
   }

   /* undisplay our window */
   //XUnmapWindow(XtDisplay(w),XtWindow(topLevel));
   /* call mtink on the remote computer */
   callCommand(pos,w);
   
   exit(0);
}

/*********************************************************************
 * Function: getResource
 *
 * read the resource
 *
 * Input: Widget  w
 *        char   *resource
 *
 * Return: char *resource
 *
 ********************************************************************/

char *getResource(Widget w, char *resource)
{
    XrmDatabase   database;
    char        *type_return;
    XrmValue     value_return;
    Widget       top = w;
    char        *tmp;
    char        *first;
    char        *last = strdup(resource);

    /* build the full resource name */
    while( !XtIsShell(top) )
    {
       tmp = XtName(top);
       first = (char*)calloc(strlen(tmp)+strlen(last)+2,1);
       sprintf(first, "%s.%s",tmp,last);
       free(last);
       last = first;
       top = XtParent(top);
    }

    /* get the class name */
    XtGetApplicationNameAndClass(XtDisplay(w), &type_return, &tmp);

    /* and complete the name */
    first = (char*)calloc(strlen(tmp)+strlen(last)+2,1);
    sprintf(first, "%s.%s",tmp,last);
    free(last);

    /* get Database */
    database = XtDatabase(XtDisplay(w));

    /* get value from the resource database,the class ist not */
    /* is not important here                                  */
    XrmGetResource(database, first,
             "String", &type_return, &value_return);

    free(first);
    return value_return.addr;

}

/*******************************************************************/
/* Function fillList(Widget list, int n, nodes_t *nodes)           */
/*                                                                 */
/* Put a further more entry (New) at the end of list               */
/*                                                                 */
/*******************************************************************/

void fillList(Widget list, int n, nodes_t *nodes)
{
   XmString *table;
   int i, j;
   char buf[1024];
   char *new = NULL;
   
   table = (XmString*)calloc(sizeof(XmString), n+1);
   
   for ( i = 0; i < n; i++ )
   {
      sprintf(buf,"%2d: %s", nodes[i].confNr, nodes[i].printer);
      table[i] = XmStringCreateSimple(buf);
   }
   new = getResource(mainWindow,"new");
   if ( new == NULL ) new = "NEW PRINTER";

   /* look for the first number which is free */
   for ( j = 0; j < n; j++ )
   {
      if ( nodes[j].confNr != j )
      {
         break;
      }
   }
   nodes[i].confNr = j;
   sprintf(buf,"%2d: %s", j, new);
   table[i] = XmStringCreateSimple(buf);

   XmListAddItems(list, table, n+1, 1);
   for ( i = 0; i < n+1; i++ )
      XmStringFree(table[i]);
   free(table);
   XmListSelectPos(list,1, False);
}

/*******************************************************************/
/* Function createLayout(char *language)                           */
/*                                                                 */
/* create the rmtink layot. language is the name of the top window */
/* so we will be able to have all internationalized resoiurces in  */
/* a resource file.                                                */
/*                                                                 */
/*******************************************************************/

Widget createLayout(char *language)
{
   Widget      separator;
   Arg         args[20];
   int         n = 0;
   Pixel       bg;

   mainWindow = XtVaCreateWidget(language,
                                 xmFormWidgetClass,
                                 topLevel,
                                 XmNmarginHeight, 0,
                                 XmNmarginWidth, 0,
                                 NULL);
   if (mainWindow == NULL)
   {
      return False;
   }
   XtManageChild(mainWindow);

   title_LB = XtVaCreateWidget("title_LB",
                             xmLabelWidgetClass,
                             mainWindow,
                             XmNleftAttachment,   XmATTACH_FORM,
                             XmNleftOffset,       5,
                             XmNrightAttachment,  XmATTACH_FORM,
                             XmNrightOffset,      5,
                             XmNtopAttachment,    XmATTACH_FORM,
                             XmNtopOffset,        10,
                             XmNalignment,        XmALIGNMENT_CENTER,
                             NULL);
   XtManageChild(title_LB);


   n = 0;
   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
   XtSetArg(args[n], XmNtopOffset, 5); n++;
   XtSetArg(args[n], XmNtopWidget, title_LB); n++;
   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
   XtSetArg(args[n], XmNleftOffset, 5); n++;
   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
   XtSetArg(args[n], XmNrightOffset, 5); n++;
   node_LST = XmCreateScrolledList(mainWindow, "title_LB",args,n);
   XtManageChild(node_LST);

   cancel_PB = XtVaCreateWidget("cancel_PB",
                            xmPushButtonWidgetClass,
                            mainWindow,
                            XmNleftAttachment,   XmATTACH_POSITION,
                            XmNleftOffset,       5,
                            XmNleftPosition,     65,
                            XmNrightAttachment,  XmATTACH_POSITION,
                            XmNrightOffset,      5,
                            XmNrightPosition,    95,
                            XmNbottomAttachment, XmATTACH_FORM,
                            XmNbottomOffset,     5,
                            NULL); 
   XtManageChild(cancel_PB);

   ok_PB = XtVaCreateWidget("ok_PB",
                            xmPushButtonWidgetClass,
                            mainWindow,
                            XmNleftAttachment,   XmATTACH_POSITION,
                            XmNleftOffset,       5,
                            XmNleftPosition,     5,
                            XmNrightAttachment,  XmATTACH_POSITION,
                            XmNrightOffset,      5,
                            XmNrightPosition,    35,
                            XmNbottomAttachment, XmATTACH_FORM,
                            XmNbottomOffset,     5,
                            NULL); 
   XtManageChild(ok_PB);


   separator = XtVaCreateWidget("separator",
                               xmSeparatorWidgetClass,
                               mainWindow,
                               XmNbottomAttachment,   XmATTACH_WIDGET,
                               XmNbottomOffset,       5,
                               XmNbottomWidget,       cancel_PB,
                               XmNleftAttachment,     XmATTACH_FORM,
                               XmNleftOffset,         0,
                               XmNrightAttachment,    XmATTACH_FORM,
                               XmNrightOffset,        0,
                               NULL); 
   XtManageChild(separator);
   XtVaSetValues(XtParent(node_LST), 
                 XmNbottomAttachment,   XmATTACH_WIDGET,
                 XmNbottomOffset,       5,
                 XmNbottomWidget,       separator,
                 NULL);
   /* if the scrolled list has a other bacground as thesttandasd */
   /* the scrollbar will be also colored, avoid this             */
   XtVaGetValues( mainWindow, XmNbackground, &bg,  NULL);
   XtVaSetValues( XtNameToWidget(XtParent(node_LST), "*VertScrollBar"),
                  XmNbackground, bg,
                  NULL);
                                                 
   XtAddCallback(cancel_PB, XmNactivateCallback, cancel_CB, NULL);
   XtAddCallback(ok_PB,     XmNactivateCallback, ok_CB,     NULL);
   XtAddCallback(node_LST,  XmNdefaultActionCallback, ok_CB, NULL);

   return mainWindow;
}


/*******************************************************************/
/* Function getDisplayName(int argc, char **argv)                  */
/*                                                                 */
/* look for the display name if given and remenber it              */
/*                                                                 */
/*******************************************************************/

void getDisplayName(int argc, char **argv)
{
   
   while(*argv)
   {
      if ( strcmp(*argv, "-display") == 0 )
      {
         if ( *argv )
         {
            dispString = (char*)calloc(strlen(argv[0])+strlen(argv[1])+2,1);
            sprintf(dispString,"%s %s",argv[0], argv[1]);
            break;
         }
      }
      argv++;
   }
   if ( dispString == NULL )
   {
      dispString = strdup("");
   }
}

/*******************************************************************/
/* Function main(int argc, char **argv)                            */
/*                                                                 */
/* The begin of the world                                          */
/*                                                                 */
/*******************************************************************/

int main(int argc, char **argv)
{
   Dimension     w1 = 0, w2 = 0, h1 = 0, h2 = 0;
   char         *s;
   char         *lang;
   char          tmpBuf[20];
   int           n;
   Widget        displayW;

   /* language handling, I know this is wrong */
   lang = getenv("LANG");
   if ( lang == NULL )
   {
      lang = getenv("LC_MESSAGES");
      if ( lang == NULL )
      {
         lang = getenv("LC_ALL");
      }
   }

   if ( lang )
   {
      if ( strcmp("german", lang) == 0 )
      {
         strcpy(tmpBuf,"De");
      }
      else
      {
         tmpBuf[0] = toupper(lang[0]);
         tmpBuf[1] = lang[1];
         tmpBuf[2] = '\0';
     }
   }

   /* for help files */
   strcpy(guiLanguage, tmpBuf);
   
   prgName = argv[0];
   if ( (s = strrchr(prgName, '/')) != NULL )
   {
      prgName = s + 1;
   }

   /* read our rc file */
   n = readRc(prgName, &nodes);

   /* sort the list */
   qsort(nodes, n, sizeof(nodes_t), cmpInt);

   /* look for the display name if given */
   getDisplayName(argc, argv);

   /* only 0 entry is the rc file, we have not to offer choices */
   /* call mtink now                                            */
   if ( n == 0 )
   {
      callCommand(n,topLevel);
      exit(0);
   }
   
   /* make the topLevel */
   mainResource = (char*)calloc(strlen(prgName)+3,1);
   strcpy(mainResource,prgName);
   mainResource[0] = toupper(mainResource[0]);

   topLevel = XtAppInitialize(&theApp,
                              mainResource,
                              NULL,
                              0,
                              &argc,
                              argv,
                              fallbackResources,
                              0,
                              0);

   if ( topLevel == (Widget) NULL )
   {
      fprintf(stderr,"%s: can't connect to X11\n", prgName);
      exit(1);
   }

   /* don't map now */
   XtVaSetValues(topLevel, XmNmappedWhenManaged, False, NULL);

   /* disable drag and drop */
   displayW = XmGetXmDisplay(XtDisplay(topLevel));
   XtVaSetValues(displayW, XmNdragInitiatorProtocolStyle, XmDRAG_NONE, NULL);


   createLayout(tmpBuf);
   fillList(node_LST,n,nodes);
   XtRealizeWidget(topLevel);

   /* put the main window on the middle of the screen */
   h2 = DisplayHeight(XtDisplay(topLevel),0);
   w2 = DisplayWidth(XtDisplay(topLevel),0);
 
   XtVaGetValues(topLevel,
                 XmNwidth,  &w1,
                 XmNheight, &h1,
                 NULL);

   XMoveWindow(XtDisplay(topLevel),
               XtWindow(topLevel),
               (w2-w1)/2,(h2-h1)/2);

   /* set min width and height */
   XtVaSetValues(topLevel,
                 XmNminHeight, h1,
                 XmNminWidth,  w1,
                 NULL);

   XtMapWidget(topLevel);

   XtManageChild(mainWindow);
   XtMapWidget(topLevel);
   
   /* set the focus to the list */
   XmProcessTraversal(node_LST, XmTRAVERSE_CURRENT);

   /* main loop */
   XtAppMainLoop(theApp);
   
   /* never reached */
   exit(0);
   return 0;
}

