/* Prolog interface to the morphological analyzer Morfeusz 2 (“Morfeusz Reloaded”) 
   Version for SWI Prolog release 5.6 and up (Unicode relases)

   Author: Marcin Woliński 
   This file is in the public domain. 

   To compile use this incantation on Linux:
   
   plld -v -shared -o morfeusz-swi.so morfeusz2-glueswi.cc -lmorfeusz2

   On Ubuntu 14.04 and later the line becomes:
   
   swipl-ld -v -shared -o morfeusz-swi.so morfeusz2-glueswi.cc -lmorfeusz2

   Here is how I compile the library for Windows using Linux version of MinGW32:
   i586-mingw32msvc-gcc -D_REENTRANT -D__SWI_PROLOG__ -I./ -I/usr/lib/swi-prolog/include -o morfeusz-swi.dll -shared morfeusz2-glueswi.cc  -L./ -lpl -lmorfeusz2

   SWI Prolog 6.x names its library libswipl.dll:
   i586-mingw32msvc-gcc -D_REENTRANT -D__SWI_PROLOG__ -I./ -I/usr/lib/swi-prolog/include -o morfeusz-swi.dll -shared morfeusz2-glueswi.cc  -L./ -lswipl -lmorfeusz2

   SWI Prolog 6.x, 7.x, 8.x on Win64 with 64-bit MinGW:
   To compile:
   • uncompress SWI Prolog Win64 installer in an empty directory,
   • copy morfeusz2.dll and morfeusz2-glueswi.cc to this directory,
   • execute:
   x86_64-w64-mingw32-g++ -D_REENTRANT -D__SWI_PROLOG__ -I./ -Iinclude/ -o morfeusz-swi.dll -shared morfeusz2-glueswi.cc  -Lbin/ -L./ -lswipl -lmorfeusz2

*/
#include <SWI-Prolog.h>

// The following line or the -D_GLIBCXX_USE_CXX11_ABI=0 compiler
// switch is needed with older versions of Morfeusz (before 2016)
// compiled with the old GCC ABI for std::string:
//
//#define _GLIBCXX_USE_CXX11_ABI 0

#include <string.h>
#include "morfeusz2.h"

using namespace morfeusz;

static functor_t F_interp;
static functor_t F_colon;
static Morfeusz *m_instance;

//extern "C" 
static foreign_t pl_morfeusz_analyse(term_t st, term_t at) { 
  char *tekst;
  
  if ( PL_get_chars(st, &tekst,
		    CVT_ATOM|CVT_STRING|CVT_LIST|CVT_EXCEPTION|
		    BUF_DISCARDABLE|REP_UTF8) ) { 
    ResultsIterator *r=m_instance->analyse(tekst);

    term_t l = PL_copy_term_ref(at);
    term_t elem = PL_new_term_ref();

    while(r->hasNext()) {
      MorphInterpretation i=r->next(); 

      term_t t_lemma = PL_new_term_ref();
      size_t colon_pos = i.lemma.find_last_of(':');
      if (colon_pos == std::string::npos ||
	  colon_pos < 1 ||
	  colon_pos == i.lemma.length()-1 ) {
	// lemat nie zawiera dwukropka lub zawiera go na którymś końcu:
	if (!PL_unify_term(t_lemma,
			   PL_UTF8_CHARS, i.lemma.c_str()
			   )) PL_fail;
      } else {
	if (!PL_unify_term(t_lemma,
			   PL_FUNCTOR, F_colon,
			   PL_UTF8_CHARS, i.lemma.substr(0,colon_pos).c_str(),
			   PL_UTF8_CHARS, i.lemma.substr(colon_pos+1).c_str()
			   )) PL_fail;
      }
	
      term_t interp = PL_new_term_ref();
      if ( !PL_unify_list(l, elem, l) ||
	   //	   !PL_chars_to_term(i.lemma.c_str(), t_lemma) ||
	   !PL_chars_to_term(i.getTag(*m_instance).c_str(), interp) ||
	   // i.getLabelsAsString(*morfeusz)
	   !PL_unify_term(elem,
			  PL_FUNCTOR, F_interp,
			  PL_INT, i.startNode,
			  PL_INT, i.endNode,
			  PL_UTF8_CHARS, i.orth.c_str(),
			  //PL_UTF8_CHARS, i.lemma.c_str(),
			  PL_TERM, t_lemma,
			  PL_TERM, interp/* , */
			  /* PL_UTF8_CHARS, i.getName(*m_instance).c_str() */
			  )
	   ) PL_fail;
    }
    return PL_unify_nil(l);
  }
  PL_fail;
}

extern "C" {
  install_t install() { 
    m_instance=Morfeusz::createInstance();
    m_instance->setCharset(UTF8);
    F_interp = PL_new_functor(PL_new_atom("i"), 5);
    F_colon = PL_new_functor(PL_new_atom(":"), 2);
    PL_register_foreign("morfeusz_analyse", 2, (pl_function_t)pl_morfeusz_analyse, 0);
  }
}

/* Local Variables: */
/* coding: utf-8 */
/* mode: c */
/* End: */
