package org.greenstone.gsdl3.core;

import org.greenstone.gsdl3.util.*;
import org.greenstone.gsdl3.action.*;
import org.greenstone.gsdl3.service.CollectionGroups;
// XML classes
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

// other java classes
import java.io.File;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Enumeration;

import org.apache.log4j.*;

/** The default greenstone receptionist - needs some extra info for each page */
public class DefaultReceptionist extends TransformingReceptionist
{

	static Logger logger = Logger.getLogger(org.greenstone.gsdl3.core.DefaultReceptionist.class.getName());

  // this gets set to the groupInfo service name if there is one.
  protected String groupInfoServiceName = null;

	/**
	 * add in the collection description to the page, then for each service, add
	 * in the service description
	 */
	protected void addExtraInfo(Element page)
	{
		super.addExtraInfo(page);
		// the document for the page
		Document doc = page.getOwnerDocument();
		// a new document to create messages to send to MR
		Document msg_doc = XMLConverter.newDOM();
		Element page_request = (Element) GSXML.getChildByTagName(page, GSXML.PAGE_REQUEST_ELEM);
		// if it is a system request, then we don't bother with this.
		String action = page_request.getAttribute(GSXML.ACTION_ATT);
		if (action.equals("s"))
		{
		    ///logger.error("HACK: don't ask for coll info if system action");
			return;
		}
		///logger.debug("add extra info, page request=" + this.converter.getString(page_request));
		// is a collection defined?
		Element param_list = (Element) GSXML.getChildByTagName(page_request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
		if (param_list == null)
		{ // must be the original home page
		    //logger.debug(" no param list, assuming home page");
			return;
		}
                HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
		HashMap<String,String> prev_params = (HashMap<String,String>)params.get(GSParams.PREVIOUS_PREFIX);
                String coll_name = (String)params.get(GSParams.COLLECTION);
		if (coll_name == null || coll_name.equals(""))
		{
                  // try p.c
                  if (prev_params != null) {
                    coll_name = prev_params.get(GSParams.COLLECTION);
                  }
                }

                if (coll_name == null || coll_name.equals(""))
                {
		    //                  logger.debug(" coll/p.c params both empty, not adding extra info");
                  return;
		}

		UserContext userContext = new UserContext(page_request);

		boolean get_service_description = false;
		Element page_response = (Element) GSXML.getChildByTagName(page, GSXML.PAGE_RESPONSE_ELEM);

		Element coll_description = (Element) GSXML.getChildByTagName(page_response, GSXML.COLLECTION_ELEM);
		if (coll_description == null)
		{
			// try cluster
			coll_description = (Element) GSXML.getChildByTagName(page_response, GSXML.CLUSTER_ELEM);
		}
		if (coll_description == null)
		{
		  //logger.debug("getting the coll description");
			// we dont have one yet - get it

			Element coll_about_message = msg_doc.createElement(GSXML.MESSAGE_ELEM);
			Element coll_about_request = GSXML.createBasicRequest(msg_doc, GSXML.REQUEST_TYPE_DESCRIBE, coll_name, userContext);
			coll_about_message.appendChild(coll_about_request);

			Node coll_about_response_message = this.mr.process(coll_about_message);
			Element coll_about_response = (Element) GSXML.getChildByTagName(coll_about_response_message, GSXML.RESPONSE_ELEM);
			if (coll_about_response == null)
			{
				return;
			}
			coll_description = (Element) GSXML.getChildByTagName(coll_about_response, GSXML.COLLECTION_ELEM);
			if (coll_description == null)
			{ // may be a cluster
				coll_description = (Element) GSXML.getChildByTagName(coll_about_response, GSXML.CLUSTER_ELEM);
			}

			if (coll_description == null)
			{
				logger.error(" no collection description, returning");
				return;
			}
			// have found one, append it to the page response
			coll_description = (Element) doc.importNode(coll_description, true);
			page_response.appendChild(coll_description);
			get_service_description = true;
		}
		
                // have we got group param, and pathList??
                String group = (String)params.get(GSParams.GROUP);
		if (group == null || group.equals("")) {
		    // try p.group
		    if (prev_params != null) {
			group = prev_params.get(GSParams.GROUP);
		    }

		}
                if (group != null && !group.equals("")) {
                  // ...yes we do. add group path info if not already present
                  Element path_list = (Element) GSXML.getChildByTagName(page_response, GSXML.PATH_ELEM + GSXML.LIST_MODIFIER);
                  if (path_list == null) {
                    // lets get it now

                    Element group_info_response = getGroupInfo(group, userContext);
                    if (group_info_response != null) {
                      path_list = (Element) GSXML.getChildByTagName(group_info_response,GSXML.PATH_ELEM + GSXML.LIST_MODIFIER);
                      if (path_list != null) {
                        page_response.appendChild(doc.importNode(path_list, true));
                      }
                    }
                  }
                }

		// have got a coll description
		// now get the dispay info for the services
		Element service_list = (Element) GSXML.getChildByTagName(coll_description, GSXML.SERVICE_ELEM + GSXML.LIST_MODIFIER);
		if (service_list == null)
		{
			logger.error(" no service list, returning");
			// something weird has gone wrong
			return;
		}

		NodeList services = service_list.getElementsByTagName(GSXML.SERVICE_ELEM);
		if (services.getLength() == 0)
		{
			logger.error("DefaultReceoptionist: no services found for colllection/cluster " + coll_name);
			return;
		}
		// check one service for display items
		if (!get_service_description)
		{
			// we dont know yet if we need to get these
			int i = 1;
			Element test_s = (Element) services.item(0);
			while (i < services.getLength() && (test_s.getAttribute(GSXML.TYPE_ATT).equals(GSXML.SERVICE_TYPE_RETRIEVE) || test_s.getAttribute(GSXML.TYPE_ATT).equals(GSXML.SERVICE_TYPE_OAI)))
			{
				test_s = (Element) services.item(i);
				i++;
			}
			if (i == services.getLength())
			{
				// we have only found retrieve or oai services, so dont need descripitons anyway
				return;
			}
			if (GSXML.getChildByTagName(test_s, GSXML.DISPLAY_TEXT_ELEM) != null)
			{
				// have got descriptions already, 
				return;
			}
		}

		// if get here, we need to get the service descriptions

		// we will send all the requests in a single message
		Element info_message = msg_doc.createElement(GSXML.MESSAGE_ELEM);
		for (int i = 0; i < services.getLength(); i++)
		{
			Element c = (Element) services.item(i);
			String name = c.getAttribute(GSXML.NAME_ATT);
			String address = GSPath.appendLink(coll_name, name);
			Element info_request = GSXML.createBasicRequest(msg_doc, GSXML.REQUEST_TYPE_DESCRIBE, address, userContext);
			//Element req_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
			//req_param_list.appendChild(GSXML.createParameter(this.doc, GSXML.SUBSET_PARAM, GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER));
			//info_request.appendChild(req_param_list);
			info_message.appendChild(info_request);

		}

		Element info_response = (Element) this.mr.process(info_message);

		NodeList service_responses = info_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
		// check that have same number of responses as collections
		if (services.getLength() != service_responses.getLength())
		{
			logger.error(" didn't get a response for each service - somethings gone wrong!");
			// for now, dont use the metadata
		}
		else
		{
			for (int i = 0; i < services.getLength(); i++)
			{
				Element c1 = (Element) services.item(i);
				Element c2 = (Element) GSXML.getChildByTagName((Element) service_responses.item(i), GSXML.SERVICE_ELEM);
				if (c1 != null && c2 != null && c1.getAttribute(GSXML.NAME_ATT).equals(c2.getAttribute(GSXML.NAME_ATT)))
				{
					//add the service data into the original response
					GSXML.mergeElements(c1, c2);
				}
				else
				{
					logger.debug(" response does not correspond to request!");
				}

			}
		}
	}

  // copied from pageaction - put in a single place
    /** sends a request to GroupCurrentContent service to get group info. null group will give top level info,
      otherwise will just give info for specified group */
  protected Element getGroupInfo(String group, UserContext userContext) {

    if (groupInfoServiceName == null) {
      // this is the first time we have come here, set this up
      
      if (this.mr instanceof MessageRouter && ((MessageRouter)this.mr).pingModule(CollectionGroups.GROUP_CONTENT_SERVICE)) {
        this.groupInfoServiceName = CollectionGroups.GROUP_CONTENT_SERVICE;
      } else {
        this.groupInfoServiceName = "NO_GROUPS";
      }
    }
    if (this.groupInfoServiceName.equals ("NO_GROUPS")) {
      return null;
    }
    // otherwise lets get the group info
    Document doc = XMLConverter.newDOM();
    // collections and groups list
    Element group_info_message = doc.createElement(GSXML.MESSAGE_ELEM);
    Element group_info_request = GSXML.createBasicRequest(doc, GSXML.TO_ATT, this.groupInfoServiceName, userContext);
    group_info_message.appendChild(group_info_request);
    if (group != null) {
      Element param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
      GSXML.addParameterToList(param_list, GSParams.GROUP, group);
      group_info_request.appendChild(param_list);
    }
    // send off the request
    Element group_info_response_message = (Element) this.mr.process(group_info_message);
    Element group_info_response = (Element) GSXML.getChildByTagName(group_info_response_message, GSXML.RESPONSE_ELEM);
    return group_info_response;
  }

}
