/**
 *############################################################################
 * 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.*;
import java.util.*;
import org.greenstone.gatherer.gui.MetadataImportMappingPrompt;
import org.greenstone.gatherer.Gatherer;


/** This class is a static class that manages the metadata sets */
public class MetadataSetManager
{
    static public final String EXTRACTED_METADATA_NAMESPACE = "ex";
    static public final String EXPLODED_METADATA_NAMESPACE = "exp";

    static private ArrayList metadata_sets = new ArrayList();
	
	// Despite being static, this class member var will only be instantiated on
	// the Event Dispatch Thread when needed and nulled again immediately after use
	static private MetadataImportMappingPrompt metadata_import_mapping_prompt = null;

    static public void clearMetadataSets()
    {
	metadata_sets.clear();
    }


    static public int compareMetadataElements(MetadataElement metadata_element_a, MetadataElement metadata_element_b)
    {
	// First compare the namespaces of the two metadata elements
	if (!metadata_element_a.getNamespace().equals(metadata_element_b.getNamespace())) {
	  if (metadata_element_a.getNamespace().equals(EXTRACTED_METADATA_NAMESPACE)) {
	    return 1;
	  }
	  if (metadata_element_b.getNamespace().equals(EXTRACTED_METADATA_NAMESPACE)) {
	    return -1;
	  }
	  return metadata_element_a.getNamespace().compareTo(metadata_element_b.getNamespace());
	}

	// Otherwise compare the two elements within the one set
	MetadataSet metadata_set = getMetadataSet(metadata_element_a.getNamespace());
	return metadata_set.compareMetadataElements(metadata_element_a, metadata_element_b);
    }


    static public ArrayList getEveryMetadataSetElement()
    {
	ArrayList every_metadata_set_element = new ArrayList();

	for (int i = 0; i < metadata_sets.size(); i++) {
	    MetadataSet metadata_set = (MetadataSet) metadata_sets.get(i);
	    every_metadata_set_element.addAll(metadata_set.getMetadataSetElements());
	}

	return every_metadata_set_element;
    }


    static public MetadataSet getMetadataSet(String metadata_set_namespace)
    {
	// Find the desired metadata set in the list
	for (int i = 0; i < metadata_sets.size(); i++) {
	    MetadataSet metadata_set = (MetadataSet) metadata_sets.get(i);
	    if (metadata_set.getNamespace().equals(metadata_set_namespace)) {
		return metadata_set;
	    }
	}

	// Not found
	return null;
    }


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


    static public ArrayList listMetadataSets(File directory)
    {
	// Make sure the directory (metadata) exists
	if (directory.exists() == false) {
	    return null;
	}

	// Load just those .mds files in this directory, and return them
	ArrayList directory_metadata_sets = new ArrayList();
	File[] directory_files = directory.listFiles();
	for (int i = 0; i < directory_files.length; i++) {
	    File child_file = directory_files[i];
	    if (!child_file.isDirectory() && child_file.getName().endsWith(".mds")) {
		MetadataSet metadata_set = new MetadataSet(child_file);
		directory_metadata_sets.add(metadata_set);
	    }
	}

	return directory_metadata_sets;
    }


    static public void loadMetadataSets(File directory)
    {
	// Make sure the directory (metadata) exists
	if (directory.exists() == false) {
	    return;
	}

	// Look recursively at each subfile of the directory for .mds files
	File[] directory_files = directory.listFiles();
	for (int i = 0; i < directory_files.length; i++) {
	    File child_file = directory_files[i];
	    if (child_file.isDirectory()) {
		loadMetadataSets(child_file);
	    }
	    else if (child_file.getName().endsWith(".mds")) {
		loadMetadataSet(child_file);
	    }
	}
    }


    static public void loadMetadataSet(File metadata_set_file)
    {
	MetadataSet metadata_set = new MetadataSet(metadata_set_file);

	// Ignore legacy crap
	if (metadata_set.getNamespace().equals("hidden")) {
	    return;
	}

	metadata_sets.add(metadata_set);
    }


    static public String mapUnloadedMetadataElement(String metadata_element_name_full)
    {
	// Check if we have an import mapping for this metadata element
	String target_metadata_element_name_full = ProfileXMLFileManager.getMetadataElementFor(metadata_element_name_full);
	if (target_metadata_element_name_full != null) {
	    // Yes, so return it
	    return target_metadata_element_name_full;
	}

	// If there are no metadata sets (except extracted) loaded then there is nothing to map the element into
	if (metadata_sets.size() <= 1) {
	    return null;
	}
	
	// Ask the user how they want to deal with this element
	Gatherer.invokeInEDT_replacesProceedInCurrThread(
		"MetadataSetManager.mapUnloadedMetadataElement() - metadata_import_mapping_prompt",
		Gatherer.SYNC,
		new Runnable() {
			public void run() {
				metadata_import_mapping_prompt = new MetadataImportMappingPrompt(metadata_element_name_full);
			}
		});
	int result = metadata_import_mapping_prompt.getResult();

	// Add the element into an existing metadata set
	if (result == MetadataImportMappingPrompt.ADD_BUTTON_PRESSED) {
	    MetadataSet target_metadata_set = metadata_import_mapping_prompt.getSelectedMetadataSet();
	    String metadata_element_name = MetadataTools.getMetadataElementName(metadata_element_name_full);
	    target_metadata_set.addMetadataElementForThisSession(metadata_element_name);
	    target_metadata_element_name_full = target_metadata_set.getNamespace() + "." + metadata_element_name;
	}

	// Replace the element with an element in an existing metadata set
	if (result == MetadataImportMappingPrompt.MERGE_BUTTON_PRESSED) {
	    MetadataElement target_metadata_element = metadata_import_mapping_prompt.getSelectedMetadataElement();
	    target_metadata_element_name_full = target_metadata_element.getFullName();
	}

	// Ignore the element
	if (result == MetadataImportMappingPrompt.IGNORE_BUTTON_PRESSED) {
	    target_metadata_element_name_full = "";
	}
	// metadata_import_mapping_prompt used to be a variable local to this function,
	// but had to become a class member var in order to do its work on the EDT and to be
	// able to access its fields and methods after. Finished using var metadata_import_mapping_prompt,
	// so set to null now, that the code may behave as before the necessary EDT change.
	metadata_import_mapping_prompt = null;
	
	// Store this import mapping for future elements with the same name
	ProfileXMLFileManager.mapElement(metadata_element_name_full, target_metadata_element_name_full);
	
	return target_metadata_element_name_full;
    }


    static public void unloadMetadataSet(MetadataSet metadata_set)
    {
	// Find the metadata set in the list of loaded sets, and remove it
	for (int i = 0; i < metadata_sets.size(); i++) {
	    if (metadata_set == (MetadataSet) metadata_sets.get(i)) {
		metadata_sets.remove(i);
		break;
	    }
	}
    }
}
