/**
 *############################################################################
 * 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.collection;


import java.io.*;
import javax.swing.*;
import org.greenstone.gatherer.cdm.CollectionDesignManager;
import org.greenstone.gatherer.file.FileNode;
import org.greenstone.gatherer.metadata.FilenameEncoding;
import org.greenstone.gatherer.util.JarTools;
import java.util.Set;
import java.util.Iterator;


/** This class represents one node in the collection tree. */
public class CollectionTreeNode
    extends FullCollectionTreeNode
{
    static final public ImageIcon GREEN_FILE_ICON = JarTools.getImage("greenfile.gif", true);
    
    /** Is this file a metadata database that is explodable with the explode_metadata_databases.pl script? */
    private boolean is_explodable = false;

    /** Keeps track of whether this file can be replaced with a Greenstone-generated html file.
     * To work with replace_srcdoc_with_html.pl */
    private boolean is_srcreplaceable = false;

    public CollectionTreeNode(File file)
    {
	super(file);
        // the super call will additionally call calcDisplayString() which will get any
        // applicable the filename encoding and apply it to the file's name for display.

	this.is_explodable = CollectionDesignManager.plugin_manager.isFileExplodable(file);
	// To work with replace_srcdoc_with_html.pl
	this.is_srcreplaceable = CollectionDesignManager.plugin_manager.isFileSrcReplaceable(file);
    
    }


    public FileNode addChildNode(File file)
    {
	CollectionTreeNode child_node = new CollectionTreeNode(file);
	child_node.setModel(model);
	child_node.setParent(this);
	return child_node;
    }


    public boolean isExplodable()
    {
	return is_explodable;
    }

    // To work with replace_srcdoc_with_html.pl
    public boolean isSrcReplaceable()
    {
	return is_srcreplaceable;
    }
    
	/** This method returns a string representation of the filenodes in the 
	* <i>Collection</i> Tree, that can then be displayed in the tree. If the 
	* filename encoding is specified as metadata with the file, then this
	* method will apply that to the filename's bytes to get the displayName.
	*/
    protected String calcDisplayString() {		
		// metadata.xml files in collections don't get displayed anyway
		if(file.getName().equals("metadata.xml")) { 
		    return super.calcDisplayString();
		}
		
		if(!FilenameEncoding.MULTIPLE_FILENAME_ENCODINGS_SUPPORTED) {
		    return super.calcDisplayString();
		}

		// Else: try to encode the display string from the 
		// file_to_encoding map. If that fails, just use the locale	
		String displayName = null;
		String urlEncodedPath = getURLEncodedFilePath();
		String encoding = FilenameEncoding.findFilenameEncoding(file, urlEncodedPath, false);

		// if it isn't the same as the current encoding already applied, reapply
		// it which will set the filenameEncoding again as well
		if(!encoding.equals(getFilenameEncoding())) {
		    displayName = reencodeDisplayName(encoding); // may return null
		}
		
		if(displayName == null) {
			if(FilenameEncoding.DEBUGGING) {
				displayName = getURLEncodedFileName(); 
			} else {
				displayName = super.calcDisplayString();
			}
		}
		
		return displayName;
    }

	/** Call this if the filename encoding has changed and needs to be 
	* recalculated and re-applied to the filename. This is only for display,
	* so it only gets applied to the urlEncodedFileName (not urlEncodedFilePath). 
	* Note that the filenameEncoding may not be the same as the given encoding
	* at the end of this method (in case it was a charset alias of the encoding). 
	* This method both sets and returns the displayFileName member variable. 
	* @return the reencoded display name, if the encoding was a recognised alias
	* in which case the filenameEncoding will store the canonical name.  */
    public String reencodeDisplayName(String encoding) {
		if(!FilenameEncoding.MULTIPLE_FILENAME_ENCODINGS_SUPPORTED) {
		    return displayFileName; // may still be null
		}

		filenameEncoding = encoding; // clear previous value

		if(filenameEncoding.equals("")) {
		    displayFileName = super.calcDisplayString(); // *FileNode* calcDisplayString
		    return displayFileName;
		}

		try{
		    displayFileName = new String(file.getName().getBytes(), filenameEncoding);
		} catch(Exception e) { 
			// IllegalCharsetName-, UnsupportedCharset- or UnsupportedEncoding-Exception
		    // Store the unsupported encoding, but display with filesystem (or URL) encoding
		    filenameEncoding = encoding;
			
			if(FilenameEncoding.DEBUGGING) {
				displayFileName = getURLEncodedFileName();
			} else {
				displayFileName = super.calcDisplayString(); 
			}
		} 
		return displayFileName;
    }
		
	/** Can call this upon refreshing a FileNode (this CollectionTreeNode). It makes
	* sure the display names of the visible nodes in the CollectionTree aren't stale */
    public void refreshDescendantEncodings() {
		// now recalculate encodings for all visible children
		
		// Don't bother with the encoding stuff when multiple filename encodings 
		// are not supported because the system is UTF-8 (not Native-Latin-1) and 
		// Java interprets all filename bytes as UTF-8, which destructively 
		// converts unrecognised characters (for UTF-8) into the invalid character.	

		if(!FilenameEncoding.MULTIPLE_FILENAME_ENCODINGS_SUPPORTED 
				|| child_nodes == null) 
		{
		    return;
		}		
		
		// get and apply the filename encoding, if any
		for(int i = 0; i < child_nodes.size(); i++) {
		    CollectionTreeNode child_node = (CollectionTreeNode) child_nodes.get(i);			
		    String urlEncodedPath = child_node.getURLEncodedFilePath();		
		    
		    String encoding = FilenameEncoding.findFilenameEncoding(
					child_node.getFile(), urlEncodedPath, false);
		    
		    // if current encoding is different from the existing one, re-apply encoding
		    if(!child_node.getFilenameEncoding().equals(encoding)) {
			child_node.reencodeDisplayName(encoding);
		    }
		}
    }
	
	// Unused at present
	/** Call when the filename encoding of this folder level fileNode has changed
	* and therefore the filename encodings of the descendant fileNodes have to be
	* reset (their entries in the file_to_encoding hashmap cleared), so that we know
	* to recalculate these later.  Call when deleting, moving or renaming col nodes */
    public void resetDescendantEncodings() {
		if(FilenameEncoding.MULTIPLE_FILENAME_ENCODINGS_SUPPORTED) {
		    resetDescendantEncodings(this.file, this.getURLEncodedFilePath());
		    
		    // for an actual file/folder delete, want to remove all corresponding 
			// entries from the hashtable without recalculating any encodings 
			// (files have been deleted, so no there will be no filenames to display).
			// So don't do this here: refreshDescendantEncodings();
			// It's done near the end of FileNode.map().
		}
    }
	
	// Together with the above, unused at present
    private static void resetDescendantEncodings(File f, String urlEncodedPath) 
    {
		// remove this file f's urlencoded path name from the file_to_encoding Map
		FilenameEncoding.map.remove(urlEncodedPath);
			
		if(f.isDirectory()) {
		    File[] children = f.listFiles();	    
		    for(int i = 0; i < children.length; i++) {
				urlEncodedPath = FilenameEncoding.fileToURLEncoding(children[i]);
				resetDescendantEncodings(children[i], urlEncodedPath); 
						// sets filenameEncoding var
	 	    }
		}
    }

}
