/**
 *############################################################################
 * A component of the Greenstone Librarian Interface, part of the Greenstone
 * digital library suite from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
 *
 * Copyright (C) 2004 New Zealand Digital Library Project
 *
 * 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.
 *############################################################################
 */

package org.greenstone.gatherer.metadata;


import java.io.File;
import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.util.XMLTools;
import org.greenstone.gatherer.util.StaticStrings;
import org.w3c.dom.*;


/** This class represents one Metadata element */
public class MetadataElement
{
    // Language-independent metadata element name, with namespace (eg. dc.Subject)
    private String metadata_element_name_full = null;
    private Element metadata_element_element = null;
    private MetadataValueTreeModel metadata_value_tree_model = null;
    /* this is true if the metadata element comes with a pre defined set of values */
    private boolean predefined_values = false;
    /* This restricts the user to only the predefined values */
    private boolean restricted_values = false;
  /* can we have more than one value for this metadata element per document? */
  /* default, true = yes */
  private boolean accumulating = true;
    public MetadataElement(String metadata_element_name_full, Element metadata_element_element)
    {
	this.metadata_element_name_full = metadata_element_name_full;
	this.metadata_element_element = metadata_element_element;
	this.metadata_value_tree_model = new MetadataValueTreeModel(this);
	if (metadata_element_element != null) {
	    if (metadata_element_element.getAttribute(StaticStrings.PREDEFINED_METADATA_ATTRIBUTE).equals("true")) {
		predefined_values = true;
		loadOptionList();
		if (metadata_element_element.getAttribute(StaticStrings.RESTRICTED_METADATA_ATTRIBUTE).equals("true")) {
		    // cant have restricted values if no predefined values
		    restricted_values = true;
		}
	    }
	    if (metadata_element_element.getAttribute("accumulating").equals("false")) {
	      accumulating = false;
	    }
	}
    }
	
    // do this better
    protected boolean loadOptionList() {
	NodeList values = metadata_element_element.getElementsByTagName("Value");
	for (int i=0; i<values.getLength(); i++) {
	    String val = XMLTools.getValue(values.item(i));
	    addMetadataValue(val);
	}
	return true;
    }
    public MetadataValueTreeNode addMetadataValue(String metadata_value)
    {
	return metadata_value_tree_model.addMetadataValue(metadata_value);
    }


    public String getAttribute(String attribute_name, String language_code)
    {
	// Some extracted metadata elements may not be in ex.mds, and so have no attributes
	if (metadata_element_element == null) {
	    return null;
	}

	Element parent_element = metadata_element_element;
	boolean language_matches = false;

	NodeList language_elements_nodelist = metadata_element_element.getElementsByTagName("Language");
	for (int i = 0; i < language_elements_nodelist.getLength(); i++) {
	    Element current_language_element = (Element) language_elements_nodelist.item(i);
	    String current_language_element_code = current_language_element.getAttribute("code");
	    if (current_language_element_code.equals(language_code)) {
		// Found language; use it for the next step
		parent_element = current_language_element;
		language_matches = true;
		break;
	    }
	}

	NodeList attribute_elements_nodelist = parent_element.getElementsByTagName("Attribute");
	for (int i = 0; i < attribute_elements_nodelist.getLength(); i++) {
	    Element current_attribute_element = (Element) attribute_elements_nodelist.item(i);
	    String current_attribute_element_name = current_attribute_element.getAttribute("name");
	    if (!current_attribute_element_name.equals(attribute_name)) {
		// Move on to the next Attribute element if the name doesn't match
		continue;
	    }

	    // Check if the language matches
	    String current_attribute_element_language = current_attribute_element.getAttribute("language");
	    if (language_matches || current_attribute_element_language.equals(language_code)) {
		// Found attribute; returns its value
		return XMLTools.getElementTextValue(current_attribute_element);
	    }
	}

	return null;
    }


    /** Returns language-dependent metadata element name, with namespace (eg. dc.Subject and Keywords) */ 
    public String getDisplayName()
    {
	// now we use label, previously we used identifier
	String metadata_element_display_name = MetadataTools.getMetadataElementAttribute(this, "label", Configuration.getLanguage(), "en");
	if (metadata_element_display_name == null) {
	    // try identifier
	    metadata_element_display_name = MetadataTools.getMetadataElementAttribute(this, "identifier", Configuration.getLanguage(), "en");
	}
	// Root case (no subelements)
	if (metadata_element_name_full.indexOf(MetadataTools.SUBELEMENT_SEPARATOR) == -1) {
	    if (metadata_element_display_name != null) {
		return getNamespace() + "." + metadata_element_display_name;
	    }

	    return metadata_element_name_full;
	}

	// Recursive case (hierarchical metadata elements)
	else {
	    String parent_metadata_element_name_full = metadata_element_name_full.substring(0, metadata_element_name_full.lastIndexOf(MetadataTools.SUBELEMENT_SEPARATOR));
	    MetadataElement parent_metadata_element = MetadataTools.getMetadataElementWithName(parent_metadata_element_name_full);

	    String parent_metadata_element_display_name = parent_metadata_element_name_full;
	    if (parent_metadata_element != null) {
		parent_metadata_element_display_name = parent_metadata_element.getDisplayName();
	    }

	    if (metadata_element_display_name != null) {
		return parent_metadata_element_display_name + MetadataTools.SUBELEMENT_SEPARATOR + metadata_element_display_name;
	    }

	    return parent_metadata_element_display_name + metadata_element_name_full.substring(parent_metadata_element_name_full.length());
	}
    }


    public MetadataValueTreeModel getMetadataValueTreeModel()
    {
	return metadata_value_tree_model;
    }


    public MetadataValueTreeNode getMetadataValueTreeNode(String metadata_value)
    {
	return metadata_value_tree_model.getMetadataValueTreeNode(metadata_value);
    }


    /** Returns language-independent metadata element name, with namespace (eg. dc.Subject) */
    public String getFullName()
    {
	return metadata_element_name_full;
    }


    public String getNamespace()
    {
	return MetadataTools.getMetadataSetNamespace(metadata_element_name_full);
    }


    /** Returns language-independent metadata element name, *without* namespace (eg. Subject) */
    public String getName()
    {
	return MetadataTools.getMetadataElementName(metadata_element_name_full);
    }


    public boolean isGSExtractedMetadataElement()
    {
	return getNamespace().equals(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE);
    }

    public boolean isExtractedMetadataElement()
    {
	return getNamespace().startsWith(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE);
    }


    public boolean isPredefined() {
	return predefined_values;
    }

    public boolean isRestricted() {
	return restricted_values;
    }

  public boolean isAccumulating() {
    return accumulating;
  }
    public boolean isSubelement()
    {
	return (metadata_element_name_full.indexOf(MetadataTools.SUBELEMENT_SEPARATOR) != -1);
    }


    /** This is used to display the element in the metadata value table */
    public String toString()
    {
	return getDisplayName();
    }
}
