/* Copyright (C) 1996,1997 Robert H”hne, see COPYING.RH for details */
/* This file is part of RHIDE. */
/* This program can be used to translate the strings in a more friendly
   way. It knows about the special char '~' in keywords, so there is
   no necessary at all all, to retranslate the string, if the hotkey
   in the key has changed. It can read also any previous translated
   files to get possible translations from those files.
   It uses the conion functions for highlighting text on the screen and
   it may work (bether the color highlight may work) only on graphic cards
   wich can show correct the textcolor(7) and textbackground(7) colors.

   The program uses the great 'fstrcmp()' function from the gettext lib,
   which does a 'fuzzy' seach for finding a similar string.

   The usage is:

   msgcat [-s] [--only-similar] [-cat cat-file ] oldest-file any-newer-file potfile output-file

   where old-file(s) are the files, with existing
   translations in descending order by time, because if a file contains
   a translation, which was already found, the new one is taken.

   The file cat-file can be used to read from and to store in all the
   translations. This file can contain also translations, which are
   currently not used by the potfile.

   if -s was given, the program does not prompt fro translating, it
   translates silently all exact msgid's and the others not.

   if --only-similar is given, the program prompst only for strings,
   which are found to be similar.

*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef __DJGPP__
#include <conio.h>

static void NORM()
{
  textcolor(7);
  textbackground(0);
}

static void LIGHT()
{
  textcolor(0);
  textbackground(7);
}

#define CRLF "\r\n"
#define CR "\r"

#else

#include <curses.h>

static void NORM()
{
#if 1
  attr_set(A_NORMAL);
#endif
}

static void LIGHT()
{
#if 1
  attr_set(A_REVERSE);
#endif
}

#define CRLF "\n"
#define CR "\n"

#define cscanf scanw
#define cprintf printw

#include <unistd.h>

static int __file_exists(const char *fname)
{
  return (access(fname,R_OK) == 0);
}

#endif

#include <unistd.h>

double fstrcmp(const char *,const char *);

struct msg
{
  char *id;
  char *id_;
  char *msg;
};

struct msg *msgs = NULL;
int msg_count = 0;
static int silent = 0;
static int only_similar = 0;

/* This function returns the string without any '~', because this is a
   special case in TV programs, so if I change the hotkey for a string
   there is no need to retranslate the string.
*/
char *similar(char *msg)
{
  static char buffer[4000];
  char *t1,*t2;
  strcpy(buffer,msg);
  t1 = strchr(buffer,'~');
  while (t1)
  {
    t2 = strchr(t1+1,'~');
    if (!t2) break;
    strcpy(t1,t1+1);
    strcpy(t2-1,t2);
    t1 = strchr(buffer,'~');
  }
  return strdup(buffer);
}

static struct msg *find_msg(char *id)
{
  int i;
  for (i=0;i<msg_count;i++)
  {
    if (strcmp(msgs[i].id,id) == 0) return &msgs[i];
  }
  return NULL;
}

void add_msg(char *id,char *msg)
{
  struct msg *_msg = find_msg(id);
  if (_msg)
  {
    free(_msg->msg);
    _msg->msg = strdup(msg);
    return;
  }
  msgs = (struct msg *)realloc(msgs,sizeof(struct msg)*(msg_count+1));
  msgs[msg_count].id = strdup(id);
  msgs[msg_count].msg = strdup(msg);
  msgs[msg_count].id_ = similar(id);
  msg_count++;
}

static char MSG[4000];
static char ID[4000];
static FILE *fi,*fo;
static char LINE[4000];
static char line[4000];

int read_id(int write_it)
{
  int started = 0;
  char *start,*end;
  ID[0] = 0;
  while (fgets(LINE,4000,fi))
  {
    if (!started && strncmp(LINE,"msgid ",6) != 0)
    {
      if (write_it) fprintf(fo,"%s",LINE);
      continue;
    }
    if (started && LINE[0] != '\"') return 1;
    started = 1;
    if (write_it) fprintf(fo,"%s",LINE);
    start = strchr(LINE,'\"')+1;
    end = strrchr(LINE,'\"');
    *end = 0;
    strcat(ID,start);
  }
  return 0;
}

int read_msg()
{
  int started = 0;
  char *start,*end;
  MSG[0] = 0;
  do
  {
    if (started && LINE[0] != '\"') return 1;
    started = 1;
    start = strchr(LINE,'\"')+1;
    end = strrchr(LINE,'\"');
    *end = 0;
    strcat(MSG,start);
  } while (fgets(LINE,4000,fi));
  return 0;
}

void write_msg(char *msg)
{
  char *tmp;
  char *start = msg;
  int started = 0;
  while ((tmp = strstr(start,"\\n")) != NULL)
  {
    char c = tmp[2];
    tmp += 2;
    *tmp = 0;
    if (!started) fprintf(fo,"msgstr ");
    started = 1;
    fprintf(fo,"\"%s\"\n",start);
    *tmp = c;
    start = tmp;
  }
  if (!started) fprintf(fo,"msgstr ");
  if (!started || *start) fprintf(fo,"\"%s\"\n",start);
  fprintf(fo,"\n");
}

static void convert(char *s)
{
  char *b;
  while ((b = strchr(s,'\b')) != NULL)
  {
    strcpy(b-1,b+1);
  }
}

int fuzzy_search(char *id,char *idd)
{
  int i;
  char c;
  double best_weight;
  int best = -1;
  double weight;
  best_weight = 0.6;
  for (i=0;i<msg_count;i++)
  {
    weight = fstrcmp(id,msgs[i].id_);
    if (weight > best_weight)
    {
      best_weight = weight;
      best = i;
    }
  }
  while (best == -1)
  {
    if (only_similar) return -1;
    NORM();
    cprintf("Please translate:"CRLF"  ");
    LIGHT();
    cprintf("%s",idd);
    NORM();
    cprintf(CRLF"Enter the string: ");
    LIGHT();
    line[0] = 0;
    cscanf("%[^"CR"]",line);
    convert(line);
    NORM();
    cprintf("\nAccept ? (y)es/(n)o/(c)ancel ");
    c = tolower(getch());
    do
    {
      c = tolower(getch());
    } while (c != 'y' && c != 'n' && c != 'c');
    NORM();
    cprintf("%c"CRLF,c);
    if (c == 'y')
    {
      add_msg(idd,line);
      return msg_count-1;
    }
    if (c == 'c') return -1;
  }
  NORM();
  cprintf("translate:"CRLF"  ");
  LIGHT();
  cprintf("%s",idd);
  NORM();
  cprintf(CRLF"from"CRLF"  ");
  LIGHT();
  cprintf("%s",msgs[best].id);
  NORM();
  cprintf(CRLF"to"CRLF"             ");
  LIGHT();
  cprintf("%s",msgs[best].msg);
  NORM();
  cprintf(CRLF"??? (y)es/(n)o/(c)hange ");
  do
  {
    c = tolower(getch());
  } while (c != 'y' && c != 'n' && c != 'c');
  NORM();
  cprintf("%c"CRLF,c);
  if (c == 'y')
  {
    add_msg(idd,msgs[best].msg);
    return best;
  }
  while (c == 'c')
  {
    NORM();
    cprintf("Translation: ");
    LIGHT();
    line[0] = 0;
    cscanf("%[^"CR"]",line);
    convert(line);
    NORM();
    c = tolower(getch());
    cprintf("\nAccept ? (y)es/(n)o/(c)hange ");
    do
    {
      c = tolower(getch());
    } while (c != 'y' && c != 'n' && c != 'c');
    NORM();
    cprintf("%c"CRLF,c);
  }
  if (c == 'n') return -1;
  add_msg(idd,line);
  return msg_count-1;
}

void translate()
{
  int i;
  char *id_;
  if (ID[0] == 0)
  {
    write_msg("");
    return;
  }
  for (i=0;i<msg_count;i++)
  {
    if (strcmp(msgs[i].id,ID) == 0)
    {
      write_msg(msgs[i].msg);
      return;
    }
  }
  if (silent)
  {
    write_msg("");
    return;
  }
  id_ = similar(ID);
  for (i=0;i<msg_count;i++)
  {
    if (strcmp(msgs[i].id_,id_) == 0) // do it not silently
    {
      char c;
      NORM();
      cprintf("translate:"CRLF"  ");
      LIGHT();
      cprintf("%s",ID);
      NORM();
      cprintf(CRLF"from"CRLF"  ");
      LIGHT();
      cprintf("%s",msgs[i].id);
      NORM();
      cprintf(CRLF"to"CRLF"             ");
      LIGHT();
      cprintf("%s",msgs[i].msg);
      NORM();
      cprintf(CRLF"??? (y)es/(n)o/(c)hange ");
      do
      {
        c = tolower(getch());
      } while (c != 'y' && c != 'n' && c != 'c');
      NORM();
      cprintf("%c"CRLF,c);
      if (c == 'y')
      {
        add_msg(ID,msgs[i].msg);
        write_msg(msgs[i].msg);
        return;
      }
      while (c == 'c')
      {
        NORM();
        cprintf("Translation: ");
        LIGHT();
        line[0] = 0;
        cscanf("%[^"CR"]",line);
        convert(line);
        NORM();
        c = tolower(getch());
        cprintf("\nAccept ? (y)es/(n)o/(c)hange ");
        do
        {
          c = tolower(getch());
        } while (c != 'y' && c != 'n' && c != 'c');
        NORM();
        cprintf("%c"CRLF,c);
      }
      if (c != 'n')
      {
        add_msg(ID,line);
        write_msg(line);
        return;
      }
    }
  }
  i = fuzzy_search(id_,ID);
  if (i != -1)
    write_msg(msgs[i].msg);
  else
    write_msg("");
}

int main(int argc,char *argv[])
{
  char *catfile;
#ifdef __linux__
  initscr();
#endif
  if (argc > 1 && strcmp(argv[1],"-s") == 0)
  {
    silent = 1;
    argc--;
    argv++;
  }
  if (argc > 1 && strcmp(argv[1],"--only-similar") == 0)
  {
    only_similar = 1;
    argc--;
    argv++;
  }
  if (argc < 4) return -argc;
  if (strcmp(argv[1],"-cat") == 0)
  {
    catfile = argv[2];
    argc -= 2;
    argv += 2;
  }
  else catfile = NULL;
  if (catfile && __file_exists(catfile))
  {
    fi = fopen(catfile,"r");
    while (read_id(0))
    {
      read_msg();
      if (strlen(MSG) > 0) add_msg(ID,MSG);
    }
    fclose(fi);
  }
  while (argc > 3)
  {
    fi = fopen(argv[1],"r");
    while (read_id(0))
    {
      read_msg();
      if (strlen(MSG) > 0) add_msg(ID,MSG);
    }
    fclose(fi);
    argc--;
    argv++;
  }
  fi = fopen(argv[1],"r");
  fo = fopen(argv[2],"w");
  while (read_id(1))
  {
    read_msg();
    translate();
  }
  fclose(fi);
  fclose(fo);
  if (catfile)
  {
    int i;
    fo = fopen(catfile,"w+");
    for (i=0;i<msg_count;i++)
    {
      fprintf(fo,"msgid \"%s\"\nmsgstr \"%s\"\n\n",msgs[i].id,msgs[i].msg);
    }
    fclose(fo);
  }
#ifdef __linux__
  endwin();
#endif
  return 0;
}

