/**
 *#########################################################################
 *
 * 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.
 *
 * <BR><BR>
 *
 * Author: Shaoqun Wu, Greenstone Digital Library, University of Waikato
 *
 * <BR><BR>
 *
 * Copyright (C) 2006 New Zealand Digital Library Project
 *
 * <BR><BR>
 *
 * 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.
 *
 * <BR><BR>
 *
 * 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.
 *
 * <BR><BR>
 *
 * 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.gems;

import org.greenstone.gatherer.util.XMLTools;
import org.greenstone.gatherer.Configuration;

import org.w3c.dom.Document;
import  org.w3c.dom.Element;
import  org.w3c.dom.Text;
import  org.w3c.dom.Node;

import java.util.Observable ;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * @author Shaoqun Wu, Greenstone Digital Library, University of Waikato
 * @version 2.4
 */
public class MetadataElementModel
    extends AttributeContainer 
{
    private Element metadata_element;
    private ArrayList children;
    private MetadataElementModel parent;
    private static ArrayList listeners = new ArrayList(); 
    private MetadataSetInfo metadataSetInfo;
    private String name;
    private static int count = 0;    
    
    public MetadataElementModel(){}
    
    // do we need this one?
    public MetadataElementModel(MetadataSetInfo info){
	this(info, null);
    }
    
    public MetadataElementModel(MetadataSetInfo info, String new_name){
	super(null, GEMSConstants.ELEMENT_LANG_DEPEND_ATTR_NAMES);
	required_attribute_names = GEMSConstants.ELEMENT_REQUIRED_ATTRIBUTES;
	metadataSetInfo = info;
	children = new ArrayList(); 
	if (new_name != null) {
	    name = new_name;       
	} else {
	    name = GEMSConstants.NEW_ELEMENT+(count++);  
	}
	// add name in as an attribute - lang independent
	Attribute attr = new Attribute(GEMSConstants.NAME_ATTRIBUTE, name, true);
	attributes.add(attr);
	// also add in a default label attribute
	attr = getAttributeByNameAndLanguage(GEMSConstants.LABEL_ATTRIBUTE, Configuration.getLanguage());
	attr.setValue(name);

    }
     
    public MetadataElementModel(Element metadataElement, MetadataSetInfo info){
	super(null, null);
	required_attribute_names = GEMSConstants.ELEMENT_REQUIRED_ATTRIBUTES;
	language_dependent_attribute_names = GEMSConstants.ELEMENT_LANG_DEPEND_ATTR_NAMES;
	metadataSetInfo = info;
	metadata_element = metadataElement;
	
	children = new ArrayList(); 
	
	constructModel(metadata_element);     
	
	ArrayList child_elements =XMLTools.getChildElementsByTagName(metadata_element,GEMSConstants.ELEMENT_ELEMENT);
	
	for(int i=0;i<child_elements.size();i++){    
	    Element element = (Element)child_elements.get(i);
	    MetadataElementModel submodel = new MetadataElementModel(element,metadataSetInfo); 
	    submodel.setParent(this);    
	    children.add(submodel);
	}
    }
    
    private void constructModel(Element meta_element){
	name = meta_element.getAttribute(GEMSConstants.NAME_ATTRIBUTE);
	
	// add name in as an attribute - the only lang independent one
	Attribute attr = new Attribute(GEMSConstants.NAME_ATTRIBUTE, name, true);
	attributes.add(attr);

	// common attributes
	ArrayList attribute_nodes =XMLTools.getChildElementsByTagName(metadata_element,GEMSConstants.ATTRIBUTE_ELEMENT);
	  
	for(int i=0;i< attribute_nodes.size();i++){
	    Element attr_element = (Element)attribute_nodes.get(i);
	    String name = attr_element.getAttribute(GEMSConstants.NAME_ATTRIBUTE).trim();
	     
	    String value =  XMLTools.getElementTextValue(attr_element);
	    attr = new Attribute(name,value);
	    String lang = attr_element.getAttribute(GEMSConstants.LANGUAGE_ATTRIBUTE);
	    if (lang.equals("")) {
		// lang independent
		attr.setRequired(isAttributeRequired(name));
		attributes.add(attr);
	    } else {
		attr.setLanguage(lang);
		attr.setRequired(isLangDependentAttributeRequired(name));
		language_dependent_attributes.add(attr);
	    }  
	}
	
	//language specific attribute  
	ArrayList language_elements =XMLTools.getChildElementsByTagName(metadata_element,GEMSConstants.LANGUAGE_ELEMENT);
	  
	for(int i=0;i< language_elements.size();i++){
	    Element language_element = (Element)language_elements.get(i);
	    String lang = language_element.getAttribute(GEMSConstants.CODE_ATTRIBUTE);
	    //Attribute element
	    ArrayList subattributes =XMLTools.getChildElementsByTagName(language_element,GEMSConstants.ATTRIBUTE_ELEMENT);
	      
	    for(int j=0;j< subattributes.size();j++){
		Element attr_element = (Element)subattributes.get(j);
		String name = attr_element.getAttribute(GEMSConstants.NAME_ATTRIBUTE).trim();
		String value =  XMLTools.getElementTextValue(attr_element);
		attr = new Attribute(name,value, isLangDependentAttributeRequired(name));
		attr.setLanguage(lang);
		language_dependent_attributes.add(attr);			    
	    }
	      
	}
	  
    }
      
    public void addMetadataElementListener(MetadataElementListener msl){
	if (!listeners.contains(msl))
	    listeners.add(msl);   
    }
      

    public void removeMetadataElementListener(MetadataElementListener msl){
	listeners.remove(msl);   
    } 
      
    public void removeAllMetadataElementListeners(){
	listeners.clear();
    }
     
      
    public boolean doesChildWithThisNameExist(String name) {
	for (int i=0; i<children.size(); i++) {
	    if (name.equals(((MetadataElementModel)children.get(i)).getName())) {
		return true;
	    }
	}
	return false;
    }


    public Element getMetadataElement(){
	return metadata_element;
    }
      
    public void notifyListeners(boolean isDeleted){

	MetadataElementEvent mee = new MetadataElementEvent(this);
        if (!isDeleted){
	    mee = new MetadataElementEvent(this);
	}
	else{
	    mee = new MetadataElementEvent(null);
	}
	
	for(int i=0;i<listeners.size();i++){
	    MetadataElementListener msl = (MetadataElementListener) listeners.get(i);
            msl.metadataElementChanged(mee);          
	}
    }

    public ArrayList getChildElements(){
	return children;
    }

    public void addChild(MetadataElementModel child){
	metadataSetInfo.getMetadataSetModel().setChanged(true);
	child.setParent(this);
	children.add(child);
    }

    public void removeChild(MetadataElementModel element_model){
	metadataSetInfo.getMetadataSetModel().setChanged(true);
	children.remove(element_model);
    }
      
    public String getName(){
	return name;
    }

    public void setName(String new_name){
	metadataSetInfo.getMetadataSetModel().setChanged(true);
	name = new_name;
              
	MetadataSetModel metadata_model = metadataSetInfo.getMetadataSetModel();
	metadata_model.valueChanged();
    }

    public String getFullName(){
	if (parent == null){
	    return metadataSetInfo.getNamespace() +"."+name;
	}
	else{
	    return parent.getFullName() +"^"+ name;
	}
    }

    public void setParent(MetadataElementModel pr){
	parent = pr;
    }

    public MetadataElementModel getParent(){
	return parent;
    }

        
    public boolean moveUp(MetadataElementModel child){
	metadataSetInfo.getMetadataSetModel().setChanged(true);
	int index = children.indexOf(child);
	if (index-1 >=0){
	    children.remove(child);
	    children.add(index-1,child);
	    return true;
	}        
	return false;
    }

    public boolean moveDown(MetadataElementModel child){
	metadataSetInfo.getMetadataSetModel().setChanged(true);
	int index = children.indexOf(child);
	if (index+1 < children.size()){
	    children.remove(child);
	    children.add(index+1,child);
	    return true;
	}        

	return false;
    }

    public void save(){
	saveElement();
	 
	for(int i=0;i<children.size();i++){
	    MetadataElementModel model = (MetadataElementModel)children.get(i);
	    model.save();
	}   
	    
    }


    private void saveElement(){
	Document doc = metadataSetInfo.getMetadataSetDocument();        

	Node parent_element = null;
	  
	if (parent !=null){
	    parent_element = parent.getMetadataElement();
	}
	else{
	    parent_element = doc.getDocumentElement();
	}
	  
	  
	metadata_element = save(doc);

	parent_element.appendChild(metadata_element); 
	                           
	    
    }


    private Element save(Document doc){
	
	metadata_element = doc.createElement(GEMSConstants.ELEMENT_ELEMENT);
	metadata_element.setAttribute(GEMSConstants.NAME_ATTRIBUTE,name);
              
	//non language dependent attributes
	for(int i=0;i<attributes.size();i++){
	    Attribute attr = (Attribute)attributes.get(i);
	    if (attr.getName() == null || attr.getName().trim().equals("")) continue;
	    if (attr.getName().equals("name")) continue;
	    Element attrElement =  doc.createElement(GEMSConstants.ATTRIBUTE_ELEMENT);
	    attrElement.setAttribute(GEMSConstants.NAME_ATTRIBUTE,attr.getName());
	    attrElement.appendChild(doc.createTextNode(attr.getValue()));
	    metadata_element.appendChild(attrElement);
	}

	  
	//language dependent attributes
	ArrayList langs = getAllLanguages();
	for (int i=0;i<langs.size();i++){
	    String lang = (String)langs.get(i);
	    Element langElement =  doc.createElement(GEMSConstants.LANGUAGE_ELEMENT);
	    langElement.setAttribute(GEMSConstants.CODE_ATTRIBUTE,lang);
	    ArrayList langAttrs = getAttributesByLanguage(lang);
	    for (int j=0;j<langAttrs.size();j++){
		Attribute attr = (Attribute)langAttrs.get(j);
		Element attrElement =  doc.createElement(GEMSConstants.ATTRIBUTE_ELEMENT);
		attrElement.setAttribute(GEMSConstants.NAME_ATTRIBUTE,attr.getName());
		attrElement.appendChild(doc.createTextNode(attr.getValue()));  
		langElement.appendChild(attrElement);
	                    
	    }
	    metadata_element.appendChild(langElement);   
	}              

	return metadata_element;
           
    }

 
  
}
