/*
 *    IIIFCollection.java
 *    Copyright (C) 2019 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.collection;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.greenstone.gsdl3.core.ModuleInterface;
import org.greenstone.gsdl3.service.ServiceRack;
import org.greenstone.gsdl3.service.IIIFPMH;
import org.greenstone.gsdl3.util.GSFile;
import org.greenstone.gsdl3.util.GSXML;
import org.greenstone.gsdl3.util.GSXSLT;
import org.greenstone.gsdl3.util.IIIFXML;
import org.greenstone.gsdl3.util.SimpleMacroResolver;
import org.greenstone.gsdl3.util.UserContext;
import org.greenstone.gsdl3.util.XMLConverter;
import org.greenstone.gsdl3.util.XMLTransformer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Represents a collection for the IIIFServerBridge. This is a cut down version of Collection, as we
 * only want to load the IIIFPMH service rack, not any of the others
 * 
 */
public class IIIFCollection extends Collection
{
	static Logger logger = Logger.getLogger(org.greenstone.gsdl3.collection.IIIFCollection.class.getName());

	/** does this collection provide the IIIF service */
	protected boolean has_iiif = false;
    
	/** a reference to the IIIFPMH service rack */
	protected IIIFPMH iiif_service_rack = null;

	/**
	 * Configures the collection.
	 * 
	 * site_home and cluster_name  must be set before configure is called.
	 * 
	 * collection metadata is obtained, and services loaded.
	 * 
	 * @return true/false on success/fail
	 */
	public boolean configure()
	{
		if (this.site_home == null || this.cluster_name == null)
		{
			logger.error("Collection: site_home and collection_name must be set before configure called!");
			return false;
		}

		macro_resolver.addMacro("_httpcollection_", this.site_http_address + "/collect/" + this.cluster_name);

		Element coll_config_xml = loadCollConfigFile();
		if (coll_config_xml == null) {
		  logger.error("Collection: couldn't configure collection: " + this.cluster_name + ", " + "Couldn't load collection config file");

		  return false;
		}
		Element build_config_xml = loadBuildConfigFile();
		if (build_config_xml == null)
		{
		  logger.error("Collection: couldn't configure collection: " + this.cluster_name + ", " + "Couldn't load build config file");

		  return false;
		}
		GSXSLT.modifyCollectionConfigForDebug(coll_config_xml);

		// process the metadata and display items and default library params
		super.configureLocalData(coll_config_xml);
		super.configureLocalData(build_config_xml);
		// get extra collection specific stuff
		findAndLoadInfo(coll_config_xml, build_config_xml);

		// load up the IIIFPMH serviceRack
		configureServiceRacks(coll_config_xml, build_config_xml);

		return true;

	}

	/**
	 * whether this collection has IIIFPMH services
	 */
	public boolean hasIIIF()
	{
		return has_iiif;
	}

    
  /** add any extra info for collection from IIIFConfig.xml */
  public boolean configureIIIF(Element iiif_config) {
    // just pass the element to each service - should only be one
    return this.iiif_service_rack.configureIIIF(iiif_config);
  }

  /** override this to only load up IIIFPMH serviceRack  - don't need all the rest of them for iiif*/
	protected boolean configureServiceRackList(Element service_rack_list, Element extra_info)
	{
	  // find the IIIFPMH service
	  Element iiif_service_xml = GSXML.getNamedElement(service_rack_list, GSXML.SERVICE_CLASS_ELEM, GSXML.NAME_ATT, "IIIFPMH");
	  if (iiif_service_xml == null) {
	    return false;
	  }
	  
	  // the xml request to send to the serviceRack to query what services it provides
	  Document doc = XMLConverter.newDOM();
	  Element message = doc.createElement(GSXML.MESSAGE_ELEM);
	  Element request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_DESCRIBE, "", new UserContext());
	  message.appendChild(request);

	  if(this.iiif_service_rack == null) {
		this.iiif_service_rack = new IIIFPMH();
	  }
	  this.iiif_service_rack.setSiteHome(this.site_home);
	  this.iiif_service_rack.setSiteAddress(this.site_http_address);
	  this.iiif_service_rack.setClusterName(this.cluster_name);
	  this.iiif_service_rack.setServiceCluster(this);
	  this.iiif_service_rack.setMessageRouter(this.router);

	  // pass the xml node to the service for configuration
	  if (this.iiif_service_rack.configure(iiif_service_xml, extra_info)) {
    
	    // find out the supported service types for this service module
	    Node types = this.iiif_service_rack.process(message);
	    NodeList typenodes = ((Element) types).getElementsByTagName(GSXML.SERVICE_ELEM);
	    
	    for (int j = 0; j < typenodes.getLength(); j++)
	      {
		String service = ((Element) typenodes.item(j)).getAttribute(GSXML.NAME_ATT);
		
		if (service_map.get(service) != null)
		  {
		    char extra = '0';
		    String new_service = service + extra;
		    
		    while (service_map.get(new_service) != null)
		      {
			extra++;
			new_service = service + extra;
		      }
		    this.service_name_map.put(new_service, service);
		    service = new_service;
		    ((Element) typenodes.item(j)).setAttribute(GSXML.NAME_ATT, service);
		  }
		this.service_map.put(service, this.iiif_service_rack);
		// also add info to the ServiceInfo XML element
		this.service_list.appendChild(this.desc_doc.importNode(typenodes.item(j), true));
	      }
	    has_iiif = true;
	    return true;
	  }
	  
	  return false;
	}
}
