// Hey ! emacs, it is an -*- objective-c -*- file

/*

     Webster Command line interface.
     Copyright (C) 1994 BENOIT GRANGE.
     
     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., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include "WebsterVolume.h"
#include "WebsterWord.h"
#include <defaults/defaults.h>

const char*		pgmName;

#define DEFAULTSNAME "CommandLineWebster"

// List of defaults values
static NXDefaultsVector appDefaults = {
  // Use library defaults
  {"Codebook", "" },
  // What do we do ?
  {"SearchDictionary", "YES" },
  {"SearchThesaurus", "YES" },
  // Show ascii
  {"Mode", "ascii" },
  // Paths for the files
  {"Webster-Dictionary", 
	"/NextLibrary/References/Webster-Dictionary/Dictionary" },
  {"Webster-Thesaurus", 
	"/NextLibrary/References/Webster-Thesaurus/Thesaurus" },
  // Remember if
  {"NoticePrinted", "NO" },
  {NULL}
};

void proceed(WebsterVolume* dico, WebsterVolume* thes,
	     const char **words, const char* mode, BOOL useReference)
{
  WebsterWord*		word;

  NX_DURING

  while (*words) {
    BOOL found = NO;
    if (useReference && [dico respondsTo: @selector(defineByReference:)])
      word = [dico defineByReference: *words];
    else
      word = [dico defineWord: *words];
    if (word) {
      char* text;
      int length;
      found = YES;
      if ([word outputDefinitionAs: mode result: &text length: &length]) {
	printf("--- '%s' (%d definitions) :\n", *words, [word numberOfDefinitions]);
	fwrite(text, length, 1, stdout);
	vm_deallocate(task_self(), (vm_address_t)text, (vm_size_t)length);
      } else printf("--- '%s' failed\n", *words);
      [word free];
    }
    word = [thes defineWord: *words];
    if (word) {
      char* text;
      int length;
      found = YES;
      if ([word outputDefinitionAs: mode result: &text length: &length]) {
	printf("--- '%s' (%d definitions in thesaurus) :\n", *words, [word numberOfDefinitions]);
	fwrite(text, length, 1, stdout);
	vm_deallocate(task_self(), (vm_address_t)text, (vm_size_t)length);
      } else printf("--- '%s' failed\n", *words);
      [word free];
    }
    if (!found) printf("--- '%s' has no definition\n", *words);
    words++;
  }

  return;

  NX_HANDLER

  NXReportError(&NXLocalHandler);

  NX_ENDHANDLER
}

void printNotice()
{
  fputs("Webster commandline interface version 1.0, "
	"Copyright (C) 1994 BENOIT GRANGE.\n"
	"This program is distributed under the GNU General Public License.\n"
	"It comes with ABSOLUTELY NO WARRANTY, for details, use the -license option.\n", stderr);
  fputs([WebsterVolume libraryCopyrightString], stderr);
  fputs("\n", stderr);
  fputs([WebsterVolume volumeCopyrightString], stderr);
}

void printLicense()
{
  printNotice(); 

  fputs(
	"     \n"
	"     This program is free software; you can redistribute it and/or\n"
	"     modify it under the terms of the GNU General Public License\n"
	"     as published by the Free Software Foundation; either version 2\n"
	"     of the License, or (at your option) any later version.\n"
	"     \n"
	"     This program is distributed in the hope that it will be useful,\n"
	"     but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
	"     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
	"     GNU General Public License for more details.\n"
	"     \n"
	"     You should have received a copy of the GNU General Public License\n"
	"     along with this program; if not, write to the Free Software\n"
	"     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
	"\n"
	, stderr);
}

void printUsage()
{
  printNotice();
  fprintf(stderr, "Usage: %s [-license] [-d][-t][-r][-c] [words]\n", pgmName);
  exit(-1);
}

#ifdef DEBUG
void ignore()
{
  fputs("<CONTINUING>\n", stderr);
}
#endif

int main(int argc, const char** argv)
{
  WebsterVolume*	dictionary= NULL;
  WebsterVolume*	thesaurus = NULL;
  BOOL			useDictionary = YES;
  BOOL			useReference = NO;
  BOOL			useThesaurus = YES;
  BOOL			findCompletions = NO;
  const char*		mode;
#ifdef DEBUG
  BOOL			debug = NO;
#endif

  pgmName = *argv++;

  NXRegisterDefaults(DEFAULTSNAME, appDefaults);

  if (!strcmp(NXGetDefaultValue(DEFAULTSNAME, "NoticePrinted"), "NO")) {
    printNotice();
    NXWriteDefault(DEFAULTSNAME, "NoticePrinted", "YES");
  }

#ifdef DEBUG
  if (*argv && !strcmp(*argv, "-debug")) {
    debug = YES;
    argv++;
  }
#endif

  if (*argv && !strcmp(*argv, "-license")) {
    printLicense();
    argv++;
  }

  if (!strcmp(NXGetDefaultValue(DEFAULTSNAME, "SearchDictionary"), "NO")) {
    useDictionary = NO;
  } else if (!strcmp(NXGetDefaultValue(DEFAULTSNAME, "SearchDictionary"), "YES")) {
    useDictionary = YES;
  } else {
    fprintf(stderr, "%s: Warning: allowed values for default 'SearchDictionary' are 'YES' or 'NO'\n",
	    pgmName);
  }

  if (!strcmp(NXGetDefaultValue(DEFAULTSNAME, "SearchThesaurus"), "NO")) {
    useThesaurus = NO;
  } else if (!strcmp(NXGetDefaultValue(DEFAULTSNAME, "SearchThesaurus"), "YES")) {
    useThesaurus = YES;
  } else {
    fprintf(stderr, "%s: Warning: allowed values for default 'SearchThesaurus' are 'YES' or 'NO'\n",
	    pgmName);
  }

  if (*argv && !strcmp(*argv, "-t")) {
    useThesaurus = YES;
    useDictionary = NO;
    argv++;
  }

  if (*argv && !strcmp(*argv, "-d")) {
    useThesaurus = NO;
    useDictionary = YES;
    argv++;
  }

  if (*argv && !strcmp(*argv, "-r")) {
    useReference = YES;
    argv++;
  }

  if (*argv && !strcmp(*argv, "-c")) {
    findCompletions = YES;
    argv++;
  }

  if (*argv && (**argv == '-')) printUsage();

  // No need to do more
  if (!*argv) exit(0);

#ifdef DEBUG
  if (debug) {
    signal(SIGINT, ignore);
    fputs("<DEBUG PAUSE>\n", stderr);
    pause();
  }
#endif

  /*
    All main in encapsulated in an NX_DURGING/NX_HANDLER construct
    because we are not using a standard event loop.
    If we don't do this we get longjmp botchs when an error is raised.
  */

  NX_DURING

  if (strlen(NXGetDefaultValue(DEFAULTSNAME, "Codebook")))
    [WebsterVolume setCodebookFileName: NXGetDefaultValue(DEFAULTSNAME, "Codebook")];

  if (useDictionary)
    dictionary = [[WebsterDictionary alloc]
		  initFromFile: NXGetDefaultValue(DEFAULTSNAME, "Webster-Dictionary") ];
  if (useThesaurus) 
    thesaurus = [[WebsterThesaurus alloc]
		  initFromFile: NXGetDefaultValue(DEFAULTSNAME, "Webster-Thesaurus") ];

  if (findCompletions) {
    List* l = [dictionary completeWord: *argv];
    int i = 0;
    WebsterWord* w;
    while (w = [l objectAt: i++]) {
      printf("%s\n", [w word]);
    }
    [l freeObjects];
    [l free];
  } else {
    mode = NXGetDefaultValue(DEFAULTSNAME, "Mode");
    
    if ((dictionary && ![dictionary canOutputDefinitionsAs: mode]) ||
      (thesaurus && ![thesaurus  canOutputDefinitionsAs: mode]))
      fprintf(stderr, "%s: translation of entry to mode '%s' is not possible\n",
	      pgmName, mode);
    else 
      proceed(dictionary, thesaurus, argv, mode, useReference);
  }
  [dictionary free];
  [thesaurus free];
 
#ifdef DEBUG
  if (debug) {
    fputs("<DEBUG PAUSE>\n", stderr);
    pause();
  }
#endif

  return(0);

  NX_HANDLER

  NXReportError(&NXLocalHandler);

  NX_ENDHANDLER
  
  return(2);
}
