/**
 *############################################################################
 * 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 java.util.*;
import javax.swing.filechooser.*;
import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.Dictionary;
import org.greenstone.gatherer.util.XMLTools;
import org.w3c.dom.*;


/** This class represents one metadata set */
public class MetadataSet
{
    private File metadata_set_file = null;
    private ArrayList metadata_set_elements = new ArrayList();
    private String metadata_set_namespace = null;


    public MetadataSet(File metadata_set_file)
    {
	this.metadata_set_file = metadata_set_file;

	// Parse the specified metadata set file
	Document document = XMLTools.parseXMLFile(metadata_set_file);
	if (document == null) {
	    System.err.println("Error: Could not parse metadata set file " + metadata_set_file.getAbsolutePath());
	    return;
	}

	// Read the metadata set's namespace
	metadata_set_namespace = document.getDocumentElement().getAttribute("namespace");

	// Read the Element elements in the metadata set
	NodeList element_elements_nodelist = document.getElementsByTagName("Element");
	for (int i = 0; i < element_elements_nodelist.getLength(); i++) {
	    Element metadata_element_element = (Element) element_elements_nodelist.item(i);
	    String metadata_element_name = metadata_element_element.getAttribute("name");

	    // Deal with hierarchical metadata elements
	    Element parent_metadata_element_element = (Element) metadata_element_element.getParentNode();
	    while (parent_metadata_element_element.getTagName().equals("Element")) {
		String parent_metadata_element_name = parent_metadata_element_element.getAttribute("name");
		metadata_element_name = parent_metadata_element_name + MetadataTools.SUBELEMENT_SEPARATOR + metadata_element_name;
		parent_metadata_element_element = (Element) parent_metadata_element_element.getParentNode();
	    }

	    String metadata_element_name_full = metadata_set_namespace + MetadataTools.NAMESPACE_SEPARATOR + metadata_element_name;
	    metadata_set_elements.add(new MetadataElement(metadata_element_name_full, metadata_element_element));
	}
    }


    public MetadataElement addMetadataElementForThisSession(String metadata_element_name)
    {
	String metadata_element_name_full = metadata_set_namespace + MetadataTools.NAMESPACE_SEPARATOR + metadata_element_name;
	MetadataElement metadata_element = new MetadataElement(metadata_element_name_full, null);
	metadata_set_elements.add(metadata_element);
	return metadata_element;
    }


    public int compareMetadataElements(MetadataElement metadata_element_a, MetadataElement metadata_element_b)
    {
	// Extracted metadata is sorted alphabetically
	if (metadata_set_namespace.equals(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE)) {
	    return metadata_element_a.getName().compareTo(metadata_element_b.getName());
	}

	// Elements in metadata sets are sorted according to the other they are specified in the .mds file
	return metadata_set_elements.indexOf(metadata_element_a) - metadata_set_elements.indexOf(metadata_element_b);
    }

    /** we consider MetadataSets to be equal if their names and namespaces match */
    public boolean equals(Object obj) {
	if (obj instanceof MetadataSet) {
	    return toString().equals(obj.toString());
	}
	return false;
    }


    public String getAttribute(String attribute_name, String language_code)
    {
	// Parse the specified metadata set file
	Document document = XMLTools.parseXMLFile(metadata_set_file);
	if (document == null) {
	    System.err.println("Error: Could not parse metadata set file " + metadata_set_file.getAbsolutePath());
	    return null;
	}

	Element document_element = document.getDocumentElement();
	Element parent_element = document_element;
	boolean language_matches = false;

	NodeList setlanguage_elements_nodelist = document_element.getElementsByTagName("SetLanguage");
	for (int i = 0; i < setlanguage_elements_nodelist.getLength(); i++) {
	    Element current_setlanguage_element = (Element) setlanguage_elements_nodelist.item(i);
	    String current_setlanguage_element_code = current_setlanguage_element.getAttribute("code");
	    if (current_setlanguage_element_code.equals(language_code)) {
		// Found language; use it for the next step
		parent_element = current_setlanguage_element;
		language_matches = true;
		break;
	    }
	}

	NodeList attribute_elements_nodelist = parent_element.getElementsByTagName(attribute_name);
	for (int i = 0; i < attribute_elements_nodelist.getLength(); i++) {
	    Element current_attribute_element = (Element) attribute_elements_nodelist.item(i);

	    // 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;
    }


    public MetadataElement getMetadataElementWithDisplayName(String metadata_element_display_name_full)
    {
	// Find the desired metadata element in the list
	for (int i = 0; i < metadata_set_elements.size(); i++) {
	    MetadataElement metadata_element = (MetadataElement) metadata_set_elements.get(i);
	    if (metadata_element.getDisplayName().equals(metadata_element_display_name_full)) {
		return metadata_element;
	    }
	}

	// Not found
	return null;
    }


    public MetadataElement getMetadataElementWithName(String metadata_element_name)
    {
	// Find the desired metadata element in the list
	for (int i = 0; i < metadata_set_elements.size(); i++) {
	    MetadataElement metadata_element = (MetadataElement) metadata_set_elements.get(i);
	    if (metadata_element.getName().equals(metadata_element_name)) {
		return metadata_element;
	    }
	}

	// Not found
	return null;
    }


    public ArrayList getMetadataSetElements()
    {
	// We don't want anyone to modify the list, so return a copy of it
	return (ArrayList) metadata_set_elements.clone();
    }


    public File getMetadataSetFile()
    {
	return metadata_set_file;
    }


    public String getNamespace()
    {
	return metadata_set_namespace;
    }


    /** This is used to display the metadata set in the metadata import mapping and explode metadata prompts */
    public String toString()
    {
	return MetadataTools.getMetadataSetAttribute(this, "Name", Configuration.getLanguage(), "en") + " (" + metadata_set_namespace + ")";
    }


    static public class MetadataSetFileFilter
	extends FileFilter
    {
	public boolean accept(File file)
	{
	    String file_name = file.getName().toLowerCase();
	    if (file_name.endsWith(".mds") || file_name.indexOf(".") == -1) {
		return true;
	    }

	    return false;
	}


	public String getDescription()
	{
	    return Dictionary.get("MetadataSet.Files");
	}
    }
}
