/*
 *    AbstractGS3DocumentRetrieve.java
 *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
 *
 *    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.gsdl3.service;

// Greenstone classes
import org.greenstone.gsdl3.core.GSException;
import org.greenstone.gsdl3.util.GSXML;
import org.greenstone.gsdl3.util.GSFile;
import org.greenstone.gsdl3.util.GS3OID;
import org.greenstone.gsdl3.util.MacroResolver;
import org.greenstone.gsdl3.util.GS2MacroResolver;
import org.greenstone.gsdl3.util.GSConstants;
import org.greenstone.gsdl3.util.SQLQuery;

// XML classes
import org.w3c.dom.Document;
import org.w3c.dom.Element; 
import org.w3c.dom.NodeList;

// General Java classes
import java.io.File;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.Set;
import java.util.Iterator;
import java.util.ArrayList;

/** Implements the generic retrieval and classifier services for GS3 
 * collections.
 *
 * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
 * @author <a href="mailto:mdewsnip@cs.waikato.ac.nz">Michael Dewsnip</a>
 */

public abstract class AbstractGS3DocumentRetrieve
    extends AbstractDocumentRetrieve {
    protected static final String INDEX_STEM_ELEM = "indexStem";

    protected SQLQuery database = null;
    protected String index_stem = null;


    /** constructor */
    protected AbstractGS3DocumentRetrieve()
    {
	this.database = new SQLQuery();
	// set up a macro resolver
    }
    
    public void cleanUp() {
	super.cleanUp();
	this.database.closeConnection();
    }

    /** configure this service */
    public boolean configure(Element info, Element extra_info)
    {
	if (!super.configure(info, extra_info)){
	    return false;
	}

	System.out.println("Configuring AbstractGS3DocumentRetrieve...");

	// the index stem is either specified in the config file or is "index"
	Element index_stem_elem = (Element) GSXML.getChildByTagName(info, INDEX_STEM_ELEM);
	if (index_stem_elem != null) {
	    this.index_stem = index_stem_elem.getAttribute(GSXML.NAME_ATT);
	}
	if (this.index_stem == null || this.index_stem.equals("")) {
	    System.err.println("GS3MGRetrieve.configure(): indexStem element not found, stem will default to 'index'");
	    this.index_stem = "index";
	}

	// open the database for querying
	// the database name is a combination of site name and collection name

	// check that site_home is set
	if (this.site_home == null || this.site_home.equals("")) {
	    System.err.println("GS3Retrieve Error: site_home is not set, so cannot work out the site name and cannot determine the database name");
	    return false;
	}
	String site_name = this.site_home.substring(this.site_home.lastIndexOf(File.separator)+1);
	if (site_name.equals("")) {
	    System.err.println("GS3Retrieve Error: Cannot extract the site name from site home: "+this.site_home);
	    return false;
	}

	if (!database.setDatabase(site_name+"_"+this.cluster_name)) {
	    System.err.println("GS3Retrieve Error: Could not open SQL database!");
	    return false;
	}

	return true;

    }

    /** if id ends in .fc, .pc etc, then translate it to the correct id */
    protected String translateId(String node_id) {
	// should really use a sql query
	return GS3OID.translateOID(node_id);
    }
    
    /** returns the id of the root node of the document containing node node_id. . may be the same as node_id */
    protected String getRootId(String node_id) {
	return GS3OID.getTop(node_id);
    }
    
    /** returns a list of the child ids in order, null if no children */
    protected ArrayList getChildrenIds(String node_id) {
	if (GS3OID.isDocTop(node_id)) { // hack
	    node_id =  GS3OID.createOID(node_id, "1");
	}
	ArrayList documents = database.getDocumentChildren(node_id);
	if (documents == null || documents.size()==0) {
	    return null;
	}
	return documents;
    }
    
    /** returns the node id of the parent node, null if no parent */
    protected String getParentId(String node_id){
	String parent = GS3OID.getParent(node_id);
	if (parent.equals(node_id)) {
	    return null;
	}
	return parent;
    }

    /** get the metadata for the classifier node node_id
     * returns a metadataList element:
     * <metadataList><metadata name="xxx">value</metadata></metadataList>
     */
    // assumes only one value per metadata
    protected Element getMetadataList(String node_id, boolean all_metadata,
				      ArrayList metadata_names)   
	throws GSException {
	Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);

	if (all_metadata) {
	    // TODO
	    

	} else {
	    for (int m = 0; m < metadata_names.size(); m++) {
		String metadata = (String) metadata_names.get(m);
		String value = null;
		value = database.getDocumentMetadata(node_id, metadata);
		if (value != null) {
		    GSXML.addMetadata(this.doc, metadata_list, metadata, value);
		}
	    }
	}

	return metadata_list;
    }

    /** returns the structural information asked for.
     * info_type may be one of
     * INFO_NUM_SIBS, INFO_NUM_CHILDREN, INFO_SIB_POS
     */
    protected String getStructureInfo(String doc_id, String info_type) {
	return null; // not implemented yet
    }

    
    /** returns the document type of the doc that the specified node 
	belongs to. should be one of 
	GSXML.DOC_TYPE_SIMPLE, 
	GSXML.DOC_TYPE_PAGED, 
	GSXML.DOC_TYPE_HIERARCHY
    */
    protected String getDocType(String node_id) {
	boolean hierarchical = false;
	if (!GS3OID.isDocTop(node_id) || database.isHierarchicalDocument(node_id) ) {
	    hierarchical = true;
	} 
	// what about paged???
	if (!hierarchical) {
	    // a simple document
	    return GSXML.DOC_TYPE_SIMPLE;
	} else {
	    // a hierarchical doc
	    return GSXML.DOC_TYPE_HIERARCHY;
	}
	// don't have paged yet.
    }

    protected String resolveRelativeLinks(String doc_content, String doc_id) {

	String http_path  = this.site_http_address + "/collect/"+this.cluster_name;
	doc_content = doc_content.replaceAll("_httpcollection_", http_path);
	return doc_content;
	
    }

    /** returns the content of a node
     * should return a nodeContent element:
     * <nodeContent>text content or other elements</nodeContent>
     */
    abstract protected Element getNodeContent(String doc_id) throws GSException;

}   
