/**
 *#########################################################################
 *
 * A component of the Gatherer application, part of the Greenstone digital
 * library suite from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * Author: John Thompson, Greenstone Digital Library, University of Waikato
 *
 * Copyright (C) 1999 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.cdm;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.DebugStream;
import org.greenstone.gatherer.Gatherer;
import org.greenstone.gatherer.util.StaticStrings;
import org.w3c.dom.*;

/** This class is responsible for maintaining a list of assigned collection level metadata, and for allows manipulations on the aforementioned data.
 * @author John Thompson, Greenstone Digital Library, University of Waikato
 * @version 2.3d
 */
public class CollectionMetaManager 
    extends DOMProxyListModel {
    
    /** Constructor. */
    public CollectionMetaManager() {
	super(CollectionDesignManager.collect_config.getDocumentElement(), StaticStrings.COLLECTIONMETADATA_ELEMENT, new CollectionMeta(""));
	DebugStream.println("CollectionMetaManager: " + getSize() + " metadata parsed.");
    }
    /** Method to add a new piece of metadata.
     * @param metadata the new CollectionMeta
     */
    public void addMetadatum(CollectionMeta metadata) {
	if(!contains(metadata)) {
	    Element element = metadata.getElement();
	    // Locate where we should insert this new metadata. 
	    Node target_node = CollectionConfiguration.findInsertionPoint(element);
	    add(root, metadata, target_node);
	}
    }

    public CollectionMeta get(int i) {
	return (CollectionMeta) getElementAt(i);
    }

    /** Retrieve the languages in use for the metadata assigned to this collection
     * @return an TreeSet containing the languages used
     */
    public TreeSet getLanguages() {
	TreeSet result = new TreeSet();
	int size = getSize();
	for(int i = 0; i < size; i++) {
	    CollectionMeta metadata = (CollectionMeta) getElementAt(i);
	    String language = metadata.getLanguage();
	    result.add(language);
	}
	return result;
    }

    /** Retrieve all of the general metadata. */
    public ArrayList getMetadata() {
	ArrayList result = new ArrayList();
	int size = getSize();
	for(int i = 0; i < size; i++) {
	    CollectionMeta metadata = (CollectionMeta) getElementAt(i);
	    if(!metadata.getName().startsWith(StaticStrings.STOP_CHARACTER)) {
		result.add(metadata);
	    }
	}
	return result;
    }
	 
    /** Retrieve all of the metadata for the given feature, regardless of language. */
    public ArrayList getMetadata(String name) {
	ArrayList result = new ArrayList();
	int size = getSize(); // Refresh DOM Model
	for(int i = 0; i < size; i++) {
	    CollectionMeta metadata = (CollectionMeta) getElementAt(i);
	    if(metadata.getName().equals(name)) {
		result.add(metadata);
	    }
	}
	return result;
    }

    /** Retrieve the named piece of metadata, in the default language, if available. If no such metadata is available then it is created.
     * @param name the name of the metadatum to retrieve as a String
     * @return the dom Element containing the specified metadatum
     */
    public CollectionMeta getMetadatum(String name) {
	return getMetadatum(name, true);
    }

    public CollectionMeta getMetadatum(String name, boolean add_if_not_found) {
	//DebugStream.println("Get the metadata for " + name + " in the default language.");
	int size = getSize();
	for(int i = 0; i < size; i++) {
	    CollectionMeta metadatum = (CollectionMeta) getElementAt(i);
	    if(metadatum.getName().equals(name) && metadatum.getLanguage().equals(Configuration.getLanguage())) {
		DebugStream.println("Found '" + metadatum + "'");
		return metadatum;
	    }
	    else {
		//DebugStream.println("No match with: " + metadatum.getName() + " [l=" + metadatum.getLanguage() + "] \"" + metadatum.getValue() + "\"");
	    }
	    metadatum = null;
	}
	if(add_if_not_found) {
	    CollectionMeta result = new CollectionMeta(name);
	    addMetadatum(result);
	    DebugStream.println("Added new metadata: " + name);
	    return result;
	}
	else {
	    return null;
	}
    }

    /** Method to retrieve a certain piece of metadata based on its name and language.
     * @param name the name of the metadata as an Object (as it may actually be a refernce to an Index or SubIndex)
     * @param language the language of the metadata.
     * @param partial <i>true</i> to return the first partial match (ie matches name but not language).
     * @return The <strong>CollectionMeta</strong> requested, or <i>null</i> if no such metadata.
     */
    public CollectionMeta getMetadata(String name, String language, boolean partial) { 
	CollectionMeta partial_match = null;
	for(int i = 0; i < getSize(); i++) {
	    CollectionMeta metadata = (CollectionMeta) getElementAt(i);
	    Object metadata_name = metadata.getName();
	    // We test the case of an object match (ie Index to Index)...
	    if(metadata_name.equals(name)) {
		if (metadata.getLanguage().equals(language)) {
		    return metadata;
		}
		partial_match = metadata;
	    }
	}
	if(partial) {
	    return partial_match;
	}
	return null;
    }

    /** Method to remove a piece of metadata.
     * @param metadata metadata
     */
    public void removeMetadata(CollectionMeta metadata) {
	if(metadata != null) {
	    String name = metadata.getName();
	    String language = metadata.getLanguage();
	    for(int i = 0; i < getSize(); i++) {
		CollectionMeta other = (CollectionMeta) getElementAt(i);
		if(name.equals(other.getName()) && language.equals(other.getLanguage())) {
		    remove(i);
		    return;
		}
		other = null;
	    }	
	    language = null;
	    name = null;
	}
    }

    /** Removes all of the metadata with a certain name, regardless of language or value. */
    public void removeMetadata(String name) {
	for(int i = getSize(); i != 0; i--) {
	    CollectionMeta other = (CollectionMeta) getElementAt(i - 1);
	    if(name.equals(other.getName())) {
		remove(i - 1);
	    }
	    other = null;
	}	
    }

    public int size() {
	return getSize();
    }
}
