/* file rdRes.c
 *
 *  Read a resource file and handle the stuffs for internationalized
 *  printting.
 *  if the wanted text is not available in the internationalized
 *  version return the default (english).
 *
 *  Copyrights: Jean-Jacques Sarton  j.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.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <ctype.h>

#include "tres.c"

static char *msgOut     = NULL;
static char **resources = NULL;

/*******************************************************************/
/* Function mfgets()                                               */
/*                                                                 */
/* replacement for fgets, allow simple editing                     */
/*                                                                 */
/*******************************************************************/

static char *mfgets(char *buffer, int size, FILE *fp)
{
   int c;
   int i = 0;

   buffer[i] = 0;
   while( i < size-1 )
   {
      c = getc(fp);
      if ( c == '\b' )
      {
         if ( i )
         {
            i--;
            buffer[i] = 0;
            printf("%c %c",c,c);
         }
      }
      else
      {
         if ( c == '\r' || c == '\n' )
         {
            if ( c == '\r' )
               printf("\r\n");
            buffer[i++] = '\n';
            buffer[i]   = 0;
            break;
         }
         printf("%c",c);
         buffer[i++] = c;
         buffer[i]   = 0;
      }
   }
   
   return buffer;
}

/*******************************************************************/
/* Function freeArray                                              */
/*                                                                 */
/* free all memory allocated to an array of strings including      */
/* the array pointer                                               */
/*                                                                 */
/*******************************************************************/

static void freeArray(char **array, int no)
{
   int i;
   if ( array )
   {
      for ( i = 0; i < no; i++ )
      {
         if ( array[i] ) free(array[i]);
      }
      free(array);
   }
}

/*******************************************************************/
/* Function addFallback                                            */
/*                                                                 */
/* add the fallback resources to the resources read from file      */
/*                                                                 */
/*******************************************************************/

static void addFallback(int entries)
{
   int actEntries=0;
   int newEntries=0;

   if ( resources )
   {
      /* add the fallback resources to the array */
      while(resources[actEntries]) actEntries++;
      while(fallbackResources[newEntries]) newEntries++;
      resources = (char**)realloc(resources, sizeof(char**)*(actEntries + newEntries + 1));
      if ( ! resources )
      {
         resources = fallbackResources;
      }
      newEntries = 0;
      while(fallbackResources[newEntries])
         resources[actEntries++] = fallbackResources[newEntries++];
      resources[actEntries] = NULL;
      
   }
   else
   {
      resources = fallbackResources;
   }
}

/*******************************************************************/
/* Function skipSpace                                              */
/*                                                                 */
/* advance up to the first non space character and return a        */
/* pointer to this position                                        */
/*                                                                 */
/*******************************************************************/

static char *skipSpace(char *s)
{
   while ( *s && isspace(*s) )
      s++;
   return s;
}

/*******************************************************************/
/* Function terminateLine                                          */
/*                                                                 */
/* remove the trailing \n an return the line lenght                */
/*                                                                 */
/*******************************************************************/

static int terminateLine(char *s)
{
   int len = 0;
   while ( *s )
   {
      if ( *s == '\n' )
      {
         *s = '\0';
         break;
      }
      s++;
      len++;
   }
   return len;
}

/*******************************************************************/
/* Function readResourceFile                                       */
/*                                                                 */
/* read the external resource file and build our storage area      */
/*                                                                 */
/*******************************************************************/

static int readResourceFile(FILE *fp)
{
   char  buf[2048];
   char *s;
   int   len;
   int   oldLen  = 0;
   int   entries = 0;
   while(fgets(buf,sizeof(buf), fp))
   {
      len = terminateLine(buf);
      if ( entries && resources[entries-1][oldLen-1] != '\\' )
      {
         s = skipSpace(buf);
         /* correct the line lenght */
         len -= (s-buf);
         if ( *s == '!' || *s == '\0' )
            continue;
      }
      else
      {
         s = buf;
      }
   
      if ( *s == '\0' )
         continue;
      if ( resources == NULL )
      {
         resources = (char **)malloc(sizeof(char*)*(entries+2));
         if ( resources == NULL )
         {
            entries = 0;
            break;
         }
         resources[1] = NULL;
      }
      else if ( resources[entries-1][oldLen-1] != '\\' )
      {
         resources = (char **)realloc(resources, sizeof(char*)*(entries+2));
         if ( resources == NULL )
         {
            entries = 0;
            break;
         }
         resources[entries+1] = NULL;
      }

      
      if ( entries && resources[entries-1][oldLen-1] == '\\' )
      {
         /* line continuation */
         resources[entries-1] = (char*)realloc(resources[entries-1], len+oldLen+1);
         if ( resources[entries-1] == NULL )
         {
            freeArray(resources, entries);
            resources = NULL;
            entries = 0;
            break;
         }
         strcpy(&resources[entries-1][oldLen-1], s);
         oldLen += len -1;
      }
      else
      {
         resources[entries] = strdup(s);
         if ( resources[entries] == NULL )
         {
            freeArray(resources, entries);
            resources = NULL;
            entries = 0;
            break;
         }
         oldLen = len;
         entries++;
      }
   }
   return entries;
}

/*******************************************************************/
/* Function checkRessourceString                                   */
/*                                                                 */
/* compare the key with the resource string, return NULL or the    */
/* message string found                                            */
/*                                                                 */
/*******************************************************************/

static char *checkRessourceString(char *res, char *key)
{
   char *msg = NULL;
   int len = strlen(key);
   if ( strncmp(res,key,len) == 0 )
   {
      if ( res[len] == ':' )
      {
         res += len;
         res++;
         while ( *res && *res == ' ' ) res++;
         msg = res;
      }
   }
   return msg;
}

/*******************************************************************/
/* Function _searchString                                          */
/*                                                                 */
/* search a string in our resource array and return it             */
/* if localized string is not found return the default string      */
/* if nothing is found return NULL                                 */
/* convert resource strings as made by Xt                          */
/*******************************************************************/

char *_searchString(char *lang, char *key)
{
   char **msg = resources;
   char *defaultMsg   = NULL;
   char *localizedMsg = NULL;
   char  *s;
   int utf;

   while( *msg )
   {
      /* go to the first . or * character */
      s = *msg;
      while ( *s && ( *s != '.' && *s != '*' ) ) s++;
      if ( *s ) s++;
      if ( *s && lang )
      {
         if ( strstr(lang,"8" ) )
            utf = 1;
         else
            utf = 0;
         if ( !utf && s[0] == lang[0] &&  s[1] == lang[1] &&
              (s[2] == '.' || s[2] == '*')
            )
         {
            /* may be that we have found the wanted string */
            
            if ( (localizedMsg = checkRessourceString(s+3, key)) )
            {
               return localizedMsg;
            }
            
         }
         else if ( utf && s[0] == lang[0] &&  s[1] == lang[1] && s[2] == lang[2]  &&
              (s[3] == '.' || s[3] == '*')
            )
         {
            /* may be that we have found the wanted string */
            
            if ( (localizedMsg = checkRessourceString(s+4, key)) )
            {
               return localizedMsg;
            }
            
         }
         else
         {
            /* check for the default string */
            if ( ! defaultMsg )
               defaultMsg = checkRessourceString(s, key);
         }
      }
      msg++;
   }
   return defaultMsg;
}

/*******************************************************************/
/* Function searchString                                           */
/*                                                                 */
/* search a string in our resource array and return it after       */
/* converting as made by Xt                                        */
/*                                                                 */
/*******************************************************************/

char *searchString(char *lang, char *key)
{
   char *s, *t;
   char *msg = _searchString(lang, key);
   if ( msgOut )
   {
      free(msgOut);
      msgOut = NULL;
   }

   if ( msg == NULL || *msg == '\0' )
   {
      ;
   }
   else
   {
      /* replace '\*' with the correct value */
      s = msg;
      t = msgOut = (char*)calloc(strlen(s)+1,1);
      while ( *s )
      {
         switch(*s)
         {
            case '\\':
               s++;
               if ( *s == 'n' )
               {
                  *t++ = '\n';
                  s++;
               }
               else
               {
                  *t++ = *s++;
               }
            break;
            default:
               *t++ = *s++;
         }
      }
   }
   return msgOut;
}

/*******************************************************************/
/* Function printText                                              */
/*                                                                 */
/* search the string referenced by lang and key, then print it     */
/* according to the passed format arguments                        */
/*                                                                 */
/*******************************************************************/

void printText(char *fmt, char *lang, char *key)
{
   char *msg;
   msg = searchString(lang, key);
   if ( msg )
      printf(fmt, msg);
   else
      printf("\nMsg <%s> NOT FOUND !\n", key);
}

/*******************************************************************/
/* Function fprintText                                             */
/*                                                                 */
/* search the string referenced by lang and key, then print it     */
/* according to the passed format arguments                        */
/*                                                                 */
/*******************************************************************/

void fprintText(FILE *out, char *fmt, char *lang, char *key)
{
   char *msg;

   msg = searchString(lang, key);
   if ( msg )
      fprintf(out,fmt, msg);
   else
      fprintf(out,"\nMsg <%s> NOT FOUND !\n", key);
}

#define fgets mfgets

/*******************************************************************/
/* Function askYn                                                  */
/*                                                                 */
/* align head stuff, ask for yes/no or similar things              */
/* only the first choice is checked. Other inputs are              */
/* defaulted to False                                              */
/*                                                                 */
/*******************************************************************/

int askYn(char *lang, char *yn)
{
   char  in[1024];
   char *answers = searchString(lang, yn);
   char *s;

   if ( answers && *answers )
   {
      fgets(in, sizeof(in),stdin);
      s = in;
      while ( *s && isspace(*s) ) s++;
      if ( toupper(*s) == toupper(*answers) )
      {
         return 1;
      }
   }
   return 0;
}

/*******************************************************************/
/* Function askNo                                                  */
/*                                                                 */
/* align head stuff, ask for pattern no in the range first to last */
/*                                                                 */
/*******************************************************************/

int askNo(int first, int last)
{
   int number = 0;
   char  in[20];

   do
   {
      printf("%d ... %d : ", first, last);
      fgets(in,sizeof(in), stdin);
      number = atoi(in);
   } while ( !(number >= first && number <= last) );

   return number;
}

/*******************************************************************/
/* Function askForChoice                                           */
/*                                                                 */
/* Print a list of choice ans a number from 1....no                */
/* then call askNo and return the the result -1 ( 0...no-1 )       */
/*                                                                 */
/*                                                                 */
/*******************************************************************/

int askForChoice(char *lang, char *choice[], int no)
{
   int    c = 0;
   int    i;
   char **array;
   char  *s;
   array = (char**)calloc(no+1, sizeof(char*));

   for ( i = 0; i < no; i++ )
   {
      if ( choice[i] == NULL )
      {

         freeArray(array, i);
         return -1;
      }
      else
      {
         s = searchString(lang, choice[i]);
         if ( s == NULL )
            s = choice[i];
         array[i] = strdup(s);
         c = strlen(array[i]) > c ? strlen(array[i]) : c;
      }
   }
   
   /* print choice textes */
   for ( i = 0; i < no; i++ )
   {
      printf("- %*s (%2d)\n", c, array[i], i+1);
   }
   i = askNo(1,no);
   return i-1;
}

/*******************************************************************/
/* Function initResource                                           */
/*                                                                 */
/* Read textes from an external file                               */
/*                                                                 */
/*******************************************************************/

int initResource()
{
   int   i;
   int   entries;
   FILE *fp;
   char  homeFile[1024+8] = { '\0', };
   char *homePath = (char*)getenv("HOME");
   char *path[] =
   {
      homeFile,
      "/usr/lib/ttink/Ttink",
      "/usr/local/lib/ttink/Ttink",
      "/opt/mtink/Ttink",
      "./Ttink"
   };
   
   if ( homePath && strlen(homePath) < 1024 )
   {
      strcpy(homeFile,homePath);
      strcat(homeFile,"/Ttink");
   }

   for ( i = 0; i < 5; i++ )
   {
      if ( path[i] && (fp = fopen(path[i],"r")) )
      {
         /* read the file */
         entries = readResourceFile(fp);
         fclose(fp);
         addFallback(entries);
         return 1;
      }
   }
   addFallback(0);
   return 0;
}

#if RESCHECK
int searchCmp(char *key, char **res)
{
   char **cmp = res;
   char  *s;
   char  *e;
   while (*res)
   {
      s = *res;
      if ( *s == '.' || *s == '*' )
      {
         e = strchr(s, ':');
         if ( e )
         {
            if ( s[3] == '.' )
            {
               if ( strncmp(key,s+4,e-s-4) == 0)
               {
                  return 1;
               }
            }
            else
            {
               if ( strncmp(key,s+1,e-s-1) == 0)
               {
                  return;
               }
            }
         }
      }
      res++;
   }
   return 0;
}

void checkForMissing(char **refRes, char **cmpRes)
{
   char **ref = refRes;
   char   lang[20];
   char   key[100];
   char  *s;
   char  *e;
   while (*ref)
   {
      s = *ref;
      if ( *s == '.' || *s == '*' )
      {
         e = strchr(s, ':');
         if ( e )
         {
            if ( s[3] == '.' )
            {
               strncpy(key,s+4,e-s-3);
               key[e-s-3] = '\0';
            }
            else
            {
               strncpy(key,s+1,e-s);
               key[e-s] = '\0';
            }
            if ( searchCmp(key,cmpRes ) == 0 )
            {
               printf(" <.%s>\n",key);
            }
         }
      }
      ref++;
   }
}


int main(int argc, char **argv)
{
   FILE  *refFp = NULL;
   FILE  *cmpFp = NULL;
   int    entriesRef;
   int    entriesCmp;
   char **resourcesRef;
   if ( argc < 3 )
   {
      printf("Syntax: checkResource refFile cmpFile\n");
      exit(1);
   }
   if ( (refFp = fopen(argv[1],"r")) != NULL )
   {
      if ( (cmpFp = fopen(argv[2],"r")) != NULL )
      {
         entriesRef = readResourceFile(refFp);
         resourcesRef = resources;
         resources = NULL;
         entriesCmp = readResourceFile(cmpFp);
         
         printf("Missed resources\n");
         checkForMissing(resourcesRef,resources);

         printf("Resources not expected\n");
         checkForMissing(resources,resourcesRef);
         
         fclose(refFp);
         fclose(cmpFp);
      }
      else
      {
         fclose(refFp);
         printf("can't open file %s\n",argv[2]);
         exit(1);
      }
   }
   else
   {
      printf("can't open file %s\n",argv[1]);
      exit(1);
   }
   return 0;
}
#endif
