/*  $Id: language.c,v 1.24 2005/03/27 21:55:39 marcusva Exp $  
 *
 *  This file is part of LingoTeach, the Language Teaching program 
 *  Copyright (C) 2001-2004 Marcus von Appen. All right reserved.
 *
 *  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 <libxml/xpath.h>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

#include "lingoteach.h"
#include "conf.h"
#include "lesson.h"
#include "language.h"

#define QUERY_ID "//lang/@id"
#define COUNT_IDS "count(//lang)"
#define QUERY_TRANS "//lang[@id='%s']/translation[@language='%s']/text()"
#define QUERY_LANG "//lang/translation[@language='%s'][text()='%s']/../@id"

/********************
 * public functions *
 ********************/

/**
 * Gets a NULL terminated list of the available languages (based on the
 * language file set in the lingConfig). The return value should be freed 
 * using ling_strings_free().
 *
 * \param settings The lingConfig to use for looking up the languages.
 * \return A NULL terminated list of the languages.
 */
lingchar**
ling_lang_get_languages (lingConfig *settings)
{
     xmlXPathObjectPtr ptr = NULL;
     lingchar **retval = NULL;
     int i = 0;
  
     /* use the defined language file */
     ptr = xmlXPathEvalExpression (QUERY_ID,
                                   ((lingPrivateConfig *) settings->pdata)->lang);
     if (!ptr)
	  return NULL;

     /* allocate space for the language array */
     retval = xmlMalloc (sizeof (lingchar *) * (ptr->nodesetval->nodeNr + 1));
     if (!retval)
     {
	  xmlXPathFreeObject (ptr);
	  return NULL;
     }

     /* init all elements with NULL */
     while (i <= ptr->nodesetval->nodeNr)
          retval[i++] = NULL;

     /* fill the language array */
     for (i = 0; i < ptr->nodesetval->nodeNr; i++)
     {
	  retval[i] = xmlXPathCastNodeToString (ptr->nodesetval->nodeTab[i]);
	  if (!retval[i])
	  {
	       ling_strings_free (retval);
	       xmlXPathFreeObject (ptr);
	       return NULL;
	  }
     }
     retval[ptr->nodesetval->nodeNr] = NULL;
     
     xmlXPathFreeObject (ptr);
     return retval;
}

/**
 * Gets the amount of languages contained in a lingConfig.
 *
 * \param settings The lingConfig to use for looking up the languages.
 * \return The total amount of languages or -1 on failure.
 */
int
ling_lang_get_language_amount (lingConfig *settings)
{
     xmlXPathObjectPtr ptr = NULL;
     int i = 0;
  
     ptr = xmlXPathEvalExpression (COUNT_IDS,
                                   ((lingPrivateConfig *) settings->pdata)->lang);
     if (!ptr)
	  return -1;

     i = (int) xmlXPathCastToNumber (ptr);
     xmlXPathFreeObject (ptr);
     return i;
}

/**
 * Gets the translation of a language (based on the language
 * file set in the lingConfig). The return value should be freed using
 * ling_free().
 *
 * \param settings The lingConfig to use for looking up the languages.
 * \param language The language to translate.
 * \param translation The language, in which the translation should be 
 * returned.
 * \return A language translation or NULL, if none found or an error occured.
 */
lingchar*
ling_lang_get_lang_translation (lingConfig *settings, lingchar *language,
				lingchar *translation)
{
     xmlXPathObjectPtr ptr = NULL;
     lingchar *search = NULL;
     lingchar *retval = NULL;
     int len = xmlStrlen (QUERY_TRANS) + xmlStrlen (language)
                 + xmlStrlen (translation);

     search = xmlMalloc ((luint) len);
     if (!search)
	  return NULL;
     xmlStrPrintf (search, len, QUERY_TRANS, language, translation);

     /* get the matching XPath pointer */
     ptr = xmlXPathEvalExpression (search,
                                   ((lingPrivateConfig *) settings->pdata)->lang);
     xmlFree (search);
     if (!ptr)
	  return NULL;

     /* get the content */
     retval = xmlXPathCastToString (ptr);
     if (xmlStrlen (retval) == 0)
     {
          xmlFree (retval);
          return NULL;
     }

     xmlXPathFreeObject (ptr);
     return retval;
}

/**
 * Gets the language id of a translated language (based on the 
 * file set in the lingConfig). The return value should be freed using
 * ling_free().
 *
 * \param settings The lingConfig to use for looking up the languages.
 * \param translation The translated language.
 * \param language The language which was used for the translation.
 *
 * \return A language id or NULL, if none found or an error occured.
 */
lingchar*
ling_lang_get_trans_language (lingConfig *settings, lingchar *translation,
                              lingchar *language)
{
     xmlXPathObjectPtr ptr = NULL;
     lingchar *search = NULL;
     lingchar *retval = NULL;
     int len = xmlStrlen (QUERY_LANG) + xmlStrlen (translation)
                 + xmlStrlen (language);

     search = xmlMalloc ((luint) len);
     if (!search)
          return NULL;
     xmlStrPrintf (search, len, QUERY_LANG, language, translation);

#ifdef DEBUG
     printf ("trans_language query: %s\n", search);
#endif

     /* evaluate XPath statement */
     ptr = xmlXPathEvalExpression (search,
                                   ((lingPrivateConfig *) settings->pdata)->lang);
     xmlFree (search);
     if (!ptr)
          return NULL;
     
     /* get the content */
     retval = xmlXPathCastToString (ptr);
     xmlXPathFreeObject (ptr);

     return retval;
}

/**
 * Gets a list of translations of a passed language list (based on the 
 * language file set in the lingConfig). The return value should be freed 
 * using ling_strings_free().
 *
 * \param settings The lingConfig to use for looking up the languages.
 * \param languages The language list to translate.
 * \param translation The language, in which the translation should be 
 * returned.
 * \return A NULL terminated list of language translations.
 */
lingchar**
ling_lang_get_lang_translations (lingConfig *settings, lingchar **languages,
				 lingchar *translation)
{
     xmlXPathObjectPtr ptr = NULL;
     lingchar *tmp = NULL;
     lingchar *search = NULL;
     lingchar **retval = NULL;
     int i = 0;
     int s = 0;
     int len = 0;
  
     /* get size of the array */
     while (languages[i])
          i++;

     /* allocate pointers for languages */
     retval = xmlMalloc (sizeof (lingchar *) * (i + 1));
     if (!retval)
	  return NULL;
     
     /* init all elements with NULL */ 
     while (s <= i)
          retval[s++] = NULL;

     /* get the language translations */
     for (s = 0; s < i; s++)
     {
	  tmp = languages[s];

	  /* build search string */
          len = xmlStrlen (QUERY_TRANS) + xmlStrlen (tmp)
                  + xmlStrlen (translation);
	  search = xmlMalloc ((luint) len);
	  if (!search)
	  {
	       if (retval)
		    ling_strings_free (retval);
	       return NULL;
	  }
	  xmlStrPrintf (search, len, QUERY_TRANS, tmp, translation);
      
	  /* search the object */
	  ptr = xmlXPathEvalExpression (search,
                                        ((lingPrivateConfig *) settings->pdata)->lang);
	  xmlFree (search);
	  if (!ptr) /* none found, so use original one... */
               retval[s] = xmlStrdup (tmp);

	  /* copy the translation to the array */
	  retval[s] = xmlXPathCastToString (ptr);

	  /* clean up and continue */
	  xmlXPathFreeObject (ptr);
     }
     retval[i] = NULL;
     return retval;
}
