/**
 *#########################################################################
 *
 * 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 java.io.*;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import java.util.ArrayList;

import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.util.Utility;
import org.greenstone.gatherer.file.*;
import org.greenstone.gatherer.util.XMLTools;
import org.greenstone.gatherer.Dictionary;

import org.apache.xerces.parsers.*;
import org.apache.xml.serialize.*;
import org.w3c.dom.*;
import org.xml.sax.*;



/** This class is responsible for managing all the metadata sets in the collection and for providing methods for manipulating the aforementioned sets contents. 
 * @author Shaoqun Wu, Greenstone Digital Library, University of Waikato
 * @version 2.4
 */
public class MetadataSetManager
{
   
    private ArrayList mds_list = new ArrayList();                      
    
    private MetadataSetModel metadata_set_model;

    private ArrayList languageList; 

    private String current_language = GEMSConstants.DEFAULT_LANGUAGE; 

    /** Constructor. 
     * This constructor can be dangerous if launched by a Greenstone application
     * that already set up the static looking Configuration object, because
     * this constructor will subtly erase and replace any previously existing
     * carefully configured Configuration object.
     * I think this constructor would only be useful if MetadataSetManager is ever launched
     * as a standalone GS3 application.
     * If instantiating a MetadataSetManager through GEMS, use the MetadataSetManager() constructor,
     * including if GEMS is launched through GLI.
     * Also use MetadataSetManager() if creating a MetadataSetManager object through GLI.
     */
    public MetadataSetManager(String gsdl_path, String gsdl3_web_path, String gsdl3_writableweb_path) {
    	// Determine the GLI user directory path
	String gli_user_directory_path = System.getProperty("user.home") + File.separator;
	
        if (Utility.isWindows()) {
	    gli_user_directory_path += "Application Data" + File.separator + "Greenstone" + File.separator + "GLI" + File.separator;
        }
        else {
            gli_user_directory_path += ".gli" + File.separator;
        }

	new Configuration(gli_user_directory_path, gsdl_path, gsdl3_web_path, gsdl3_writableweb_path, null, null, null, null,null);         
	current_language = Configuration.getLanguage(); 

        languageList = new ArrayList();
    }
    
    /** Constructor - overloaded to use any existing Configuration already set up.
     * This Constructor is used by GEMS when GEMS is launched through GLI.
     */
    public MetadataSetManager() {    	     
	current_language = Configuration.getLanguage(); 

        languageList = new ArrayList();
    }
    
    public ArrayList getLanguageList(){
        //already loaded
	if (languageList.size() > 0 ) return languageList;
  	
	Document document = XMLTools.parseXMLFile("xml/languages.xml", true);        

	NodeList languages = document.getDocumentElement().getElementsByTagName(GEMSConstants.LANGUAGE_ELEMENT);
        for(int i=0; i< languages.getLength();i++){
            Element language_element = (Element)languages.item(i);
            languageList.add(language_element.getAttribute(GEMSConstants.CODE_ATTRIBUTE).toLowerCase()+"   "+language_element.getAttribute(GEMSConstants.NAME_ATTRIBUTE));
	}  
   
	return languageList;
    }


    public boolean isAttributeRequired(String name){
	String tmp_name = name.trim();
	for(int i=0;i<GEMSConstants.SET_REQUIRED_ATTRIBUTES.length;i++){
            if (tmp_name.equals(GEMSConstants.SET_REQUIRED_ATTRIBUTES[i])) return true;
	}
	return false;
    }

    public void save(boolean confirm) {
	MetadataSetInfo meta_info =  metadata_set_model.getMetadataSetInfo();
	
	if (meta_info ==null) return;

	if (confirm){

	    //int result = JOptionPane.showOptionDialog(null, Dictionary.get("GEMS.Confirm_Save"), Dictionary.get("GEMS.Confirm_Save_Title"), JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,null,Dictionary.get("General.No"),Dictionary.get("General.No"));
	    int result = JOptionPane.showConfirmDialog(null, Dictionary.get("GEMS.Confirm_Save"), Dictionary.get("GEMS.Confirm_Save_Title"), JOptionPane.YES_NO_OPTION);
	    if (result != JOptionPane.YES_OPTION) return;
	}
	

        File file_path = null;
	//get new file name
        if(meta_info.isNew()){
	    JFileChooser file_chooser =  new JFileChooser(new File(getGLIMetadataDirectoryPath()));
	    file_chooser.setMultiSelectionEnabled(false);
	    file_chooser.setSelectedFile(new File(getGLIMetadataDirectoryPath(), meta_info.getNamespace()+GEMSConstants.METADATA_SET_FILE_EXTENSION));
	    int result = file_chooser.showSaveDialog(null);
	    if (result == JFileChooser.APPROVE_OPTION){
		file_path = file_chooser.getSelectedFile();
		meta_info.setFilePath(file_path.toString());
		meta_info.setNew(false);
	    } 
	}
	else {
	    file_path = new File(meta_info.getFilePath());
	}

	if (file_path != null) save(file_path);

	for(int i=0;i<mds_list.size();i++){
	    MetadataSetInfo infoItem = (MetadataSetInfo)mds_list.get(i);
	    if (infoItem.getFilePath().trim().equals(meta_info.getFilePath().trim())) {
		mds_list.remove(infoItem);
		mds_list.add(meta_info); 
		break;
	    }	    
	}
	return;

    }


    private void save(File file_path){

	try {
	    
	    XMLTools.writeXMLFile(file_path, metadata_set_model.getMetadataSetDocument());
	    
	}
	catch (Exception error) {
	    error.printStackTrace();
	}
    
    }


    public Document getMetadataSetDocument(String filePath){ 
	if (filePath == null || filePath.equals("")) return null;
        return  XMLTools.parseXMLFile(filePath, true);
    }

    public void setMetadataSetModel(MetadataSetModel model){
	metadata_set_model = model;
    }

    public MetadataSetModel getMetadataSetModel(){
        return  metadata_set_model;
    }
    

    public ArrayList getAvailableMetadataSets(){
	mds_list.clear();        
	// Load all the core metadata sets (in the GLI "metadata" directory)
	File metadata_directory = new File(getGLIMetadataDirectoryPath());
	if (metadata_directory.exists()) {
	    // Load just those .mds files in this directory, and return them
	    File[] directory_files = metadata_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(GEMSConstants.METADATA_SET_FILE_EXTENSION)) {
                   Document document = XMLTools.parseXMLFile(child_file.toString(), true);
                   MetadataSetInfo info = constructMetadataInfo(document);
                   info.setFilePath(child_file.toString());                              
		   mds_list.add(info);		        	    
		}
	    }
	}

	return  mds_list;
    }

    public boolean isNamespaceAlreadyUsed(String namespace){
	for(int i=0;i<mds_list.size();i++){
	    MetadataSetInfo info = (MetadataSetInfo)mds_list.get(i);
	    if (info.getNamespace().trim().equals(namespace)) return true;	    
	}
	return false;
    }

    public MetadataSetInfo getMetadataSet(String metadata_path){
	MetadataSetInfo info = constructMetadataInfo(XMLTools.parseXMLFile(metadata_path,true));

	// check whether there is metadata set name for the current language
	// if not reset the current_language to the language first encountered
        ArrayList attrs = info.getLanguageDependentAttributes();
	boolean foundLanguage = false;
        for (int i=0;i<attrs.size();i++){
	    Attribute attr = (Attribute)attrs.get(i);
	    if (attr.getLanguage().equals(current_language)) {
		info.setCurrentLanguage(current_language);
		foundLanguage = true;
                break;
	    }
	    
	}              
        if (!foundLanguage && attrs.size()>0){
	    info.setCurrentLanguage(((Attribute)attrs.get(0)).getLanguage());
	}      
	
	info.setFilePath(metadata_path);            
        return info;

    }     
    
    public void deleteMetadataSet(MetadataSetInfo info){
	String filepath = info.getFilePath();

        if(filepath != null && !filepath.trim().equals("")){
	    File file = new File(filepath);
	  
	  boolean deleted = file.delete();
	  if (!deleted){
	        JOptionPane.showMessageDialog(null,Dictionary.get("GEMS.File_Deletion_Error_Message"), Dictionary.get("GEMS.File_Deletion_Error"),JOptionPane.ERROR_MESSAGE);
	  }
	  else{
	      	for(int i=0;i<mds_list.size();i++){
		    MetadataSetInfo infoItem = (MetadataSetInfo)mds_list.get(i);
		    if (infoItem.getFilePath().trim().equals(info.getFilePath().trim())) {
			mds_list.remove(infoItem);
			break;
		    }	    
		}
	  }
	}
    }

    public String getCurrentLanguage(){
	return current_language;
    }

    private MetadataSetInfo constructMetadataInfo(Document document){      
	NamedNodeMap attrs = document.getDocumentElement().getAttributes();
        ArrayList attrList = new ArrayList();
        String lang = null;
        boolean findLang = false;
	
        for (int i=0;i<attrs.getLength();i++){
	    Attr item = (Attr)attrs.item(i);
	    Attribute attr = new Attribute(item.getName(),item.getValue());
            attr.setRequired(isAttributeRequired(attr.getName()));
	    attrList.add(attr);
	}

	ArrayList languageList = new ArrayList();
 
        //load all <SetLanguage> elements
        NodeList setLanguages = document.getDocumentElement().getElementsByTagName(GEMSConstants.SET_LANGUAGE_ELEMENT);
	
        if (setLanguages.getLength() >0){
	    for(int i=0;i<setLanguages.getLength();i++){
		Element set_language = (Element)setLanguages.item(i);
                lang = set_language.getAttribute(GEMSConstants.CODE_ATTRIBUTE); 
		setNameAndDescription(languageList, set_language,lang); 	
	    }
	    
	}
        //no set langugae elements, try load name and description elements
        else{
            setNameAndDescription(languageList, document.getDocumentElement(),lang);     
	}
	
	MetadataSetInfo info = new MetadataSetInfo();
	info.setLanguageDependentAttributes(languageList);
	info.setAttributes(attrList);       
	return info;
    }

    private void setNameAndDescription(ArrayList languageList, Element parent,String lang){

	ArrayList names = XMLTools.getChildElementsByTagName(parent,GEMSConstants.NAME_ELEMENT);         
        String name_lang = "";       

	if (names.size() > 0){
	    Element name_element = (Element)names.get(0);
            Attribute attr = new Attribute(GEMSConstants.NAME_ATTRIBUTE,XMLTools.getElementTextValue(name_element), true);
	    if (lang == null){
		attr.setLanguage(name_element.getAttribute(GEMSConstants.LANGUAGE_ATTRIBUTE));
                name_lang = attr.getLanguage();
	    }
	    else{
		attr.setLanguage(lang); 
	    }
	    languageList.add(attr);
// 	    if (current_language.equals(attr.getLanguage())){
// 		attr.setRequired(true);
//                 languageList.add(0,attr);
// 	    }
// 	    else{
// 		languageList.add(attr);
// 	    }    
            
	}
      	
	
	ArrayList des = XMLTools.getChildElementsByTagName(parent,GEMSConstants.DESCRIPTION_ELEMENT);
	if (des.size() > 0){
	    Element des_element = (Element)des.get(0);
	    Attribute attr = new Attribute(GEMSConstants.DESCRIPTION_ATTRIBUTE,XMLTools.getElementTextValue(des_element), true); 
	    if (lang == null){
		attr.setLanguage(des_element.getAttribute(GEMSConstants.LANGUAGE_ATTRIBUTE));
	    }
	      else{
		  attr.setLanguage(lang); 
	      }
	    languageList.add(attr);
	}
	else{
	    Attribute attr = new Attribute(GEMSConstants.DESCRIPTION_ATTRIBUTE,"", true);
            if (lang == null){
		attr.setLanguage(name_lang);
	    }
	    else{
		attr.setLanguage(lang); 
	    }
	    
	    languageList.add(attr); 
	}
	
    }

    
    static public String getGLIDirectoryPath()
    {
	return System.getProperty("user.dir") + File.separator;
    }


    static public String getGLIMetadataDirectoryPath()
    {
	return getGLIDirectoryPath() + "metadata" + File.separator;
    }
  
     static public String getCollectionPath()
    {
      if (Configuration.gsdl3_web_path != null && !Configuration.gsdl3_web_path.equals("") ){
	    return Configuration.gsdl3_web_path + File.separator + "sites"; 

	}
	else{
	    return Configuration.gsdl_path + File.separator + "collect";
	}
    } 
}
