/*
 * This file is part of the Poliqarp suite.
 * 
 * Copyright (C) 2009, 2010 by Instytut Podstaw Informatyki Polskiej
 * Akademii Nauk (IPI PAN; Institute of Computer Science, Polish
 * Academy of Sciences; cf. www.ipipan.waw.pl).  All rights reserved.
 * 
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file gpl.txt included in the packaging
 * of this file.  (See http://www.gnu.org/licenses/translations.html for
 * unofficial translations.)
 * 
 * A commercial license is available from IPI PAN (contact
 * Michal.Ciesiolka@ipipan.waw.pl or ipi@ipipan.waw.pl for more
 * information).  Licensees holding a valid commercial license from IPI
 * PAN may use this file in accordance with that license.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

#include <assert.h>
#include <errno.h>
#include <string.h>

#include <foostring/foostring.h>

#include <bp/common.h>
#include <bp/ng/binary-pool.h>
#include <bp/ng/configuration.h>
#include <bp/ng/document.h>
#include <bp/ng/list.h>
#include <bp/ng/meta-key.h>
#include <bp/ng/xmlns-item.h>
#include <bp/ng/xml-parser.h>
#include <bp/ng/xpath.h>

static void collect_metadata(struct corpus_document *corpus,
   xpath_context *context, const char *id, struct meta_key *key)
{
   size_t i;
   size_t caught = 0;
   assert(corpus != NULL);
   assert(context != NULL);
   assert(key != NULL);
   for (i = 0; i < key->xmlns->length; i++) {
      struct xmlns_item *xmlns_item = key->xmlns->items[i];
      assert(xmlns_item != NULL);
      assert(xmlns_item->prefix != NULL);
      assert(xmlns_item->uri != NULL);
      xpath_register_ns(context, xmlns_item->prefix, xmlns_item->uri);
   }
   xpath_register_functions(context);
   for (i = 0; i < key->paths.length; i++) {
      const char *path = key->paths.items[i];
      assert(path != NULL);
      caught = 0;
      xpath_object *object = xpath_new(context, path);
      if (object->nodesetval != NULL) {
         int j, size = object->nodesetval->nodeNr;
         for (j = 0; j < size; j++) {
            char *value = xml_node_as_string(object->nodesetval->nodeTab[j]);
            xml_normalize_space(value);
            if (key->type == META_TYPE_ENUM) {
               if (!meta_key_has_value(key, value)) {
               assert(key->names.length > 0);
                  bp_warning("invalid value for meta key \"%s\": <%s>",
                     meta_key_get_name(key));
               }
            }
            corpus_add_meta_value(corpus, key, value);
            free(value);
            caught++;
            if (!key->multiple)
               break;
         }
      } else if (object->stringval != NULL) {
         char *value = xpath_object_as_string(object);
         xml_normalize_space(value);
         if (*value) {
            /* Don't consider if the string is empty. */
            if (key->type == META_TYPE_ENUM) {
               if (!meta_key_has_value(key, value)) {
               assert(key->names.length > 0);
                  bp_warning("invalid value for meta key \"%s\": <%s>",
                     meta_key_get_name(key));
               }
            }
            corpus_add_meta_value(corpus, key, value);
            caught++;
         }
         free(value);
      }
      xpath_free(object);
      if (caught > 0)
         break;
   }
   if (caught == 0) {
      if (key->required) {
         assert(key->names.length > 0);
         bp_warning("no metadata value for key %s", meta_key_get_name(key));
      }
      corpus_add_meta_value(corpus, key, NULL);
   }
}

void document_collect_metadata(struct document *document,
   struct corpus_document *corpus, const char *id)
{
   size_t i;
   assert(document != NULL);
   assert(corpus != NULL);
   assert(id != NULL);
   for (i = 0; i < document->meta_keys->length; i++) {
      xpath_context *context = xpath_context_new((xml_document*) document->xml_header, id);
      collect_metadata(corpus, context, id, document->meta_keys->items[i]);
      xpath_context_free(context);
   }
}

int document_parse_header(struct document *document, const struct list *meta_keys)
{
   assert(document != NULL);
   assert(meta_keys != NULL);
   char *path;
   path = string_aformat("%s/%s", document->dir_name, document->header_name);
   assert(document->xml_header == NULL);
   document->xml_header = (void*) xml_document_new(path);
   free(path);
   if (document->xml_header == NULL)
      return -1;
   assert(document->meta_keys == NULL);
   document->meta_keys = meta_keys;
   return 0;
}

void document_free_header(struct document *document)
{
   if (document->xml_header != NULL)
      xml_document_free(document->xml_header);
   document->xml_header = NULL;
   document->meta_keys = NULL;
}
