package tap.resource;

/*
 * This file is part of TAPLibrary.
 *
 * TAPLibrary is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * TAPLibrary 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2012-2016 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 *                       Astronomisches Rechen Institut (ARI)
 */

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import tap.TAPException;
import uk.ac.starlink.votable.VOSerializer;
import uws.UWSToolBox;

/**
 * <p>TAP resource describing the capabilities of a TAP service.</p>
 *
 * <p>This resource just return an XML document giving a description of the TAP service and list all its VOSI resources.</p>
 *
 * @author Gr&eacute;gory Mantelet (CDS;ARI)
 * @version 2.1 (07/2016)
 */
public class Capabilities implements TAPResource, VOSIResource {

	/** Name of this TAP resource. */
	public static final String RESOURCE_NAME = "capabilities";

	/** Representation of the whole TAP service. This object list all available resources ;
	 * resources that correspond to the capabilities this resource must list. */
	private final TAP tap;

	/** <p>URL toward this TAP resource.
	 * This URL is particularly important for its declaration in the capabilities of the TAP service.</p>
	 *
	 * <p><i>Note: By default, it is just the name of this resource. It is updated after initialization of the service
	 * when the TAP service base URL is communicated to its resources. Then, it is: baseTAPURL + "/" + RESOURCE_NAME.</i></p> */
	protected String accessURL = getName();

	/** The path of the XSLT style-sheet to apply.
	 * @since 2.1 */
	protected String xsltPath = null;

	/**
	 * Build a "/capabilities" resource.
	 *
	 * @param tap	Object representation of the whole TAP service.
	 */
	public Capabilities(final TAP tap){
		this.tap = tap;
	}

	/**
	 * Gets the path/URL of the XSLT style-sheet to use.
	 *
	 * @return	XSLT path/url.
	 *
	 * @since 2.1
	 */
	public final String getXSLTPath(){
		return xsltPath;
	}

	/**
	 * Sets the path/URL of the XSLT style-sheet to use.
	 *
	 * @param path	The new XSLT path/URL.
	 *
	 * @since 2.1
	 */
	public final void setXSLTPath(final String path){
		if (path == null)
			xsltPath = null;
		else{
			xsltPath = path.trim();
			if (xsltPath.isEmpty())
				xsltPath = null;
		}
	}

	@Override
	public final void setTAPBaseURL(String baseURL){
		accessURL = ((baseURL == null) ? "" : (baseURL + "/")) + getName();
	}

	@Override
	public final String getName(){
		return RESOURCE_NAME;
	}

	@Override
	public final String getStandardID(){
		return "ivo://ivoa.net/std/VOSI#capabilities";
	}

	@Override
	public final String getAccessURL(){
		return accessURL;
	}

	@Override
	public String getCapability(){
		return getDefaultCapability(this);
	}

	@Override
	public void init(ServletConfig config) throws ServletException{
		;
	}

	@Override
	public void destroy(){
		;
	}

	@Override
	public boolean executeResource(HttpServletRequest request, HttpServletResponse response) throws IOException, TAPException{
		/* "In the REST binding, the support interfaces shall have distinct URLs in the HTTP scheme and shall be accessible by the GET operation in the HTTP protocol.
		 * The response to an HTTP POST, PUT or DELETE to these resources is not defined by this specification. However, if an implementation has no special action
		 * to perform for these requests, the normal response would be a 405 "Method not allowed" error."
		 * (Extract of the VOSI definition: http://www.ivoa.net/documents/VOSI/20100311/PR-VOSI-1.0-20100311.html#sec2) */
		if (!request.getMethod().equalsIgnoreCase("GET"))
			throw new TAPException("The CAPABILITIES resource is only accessible in HTTP-GET! No special action can be perfomed with another HTTP method.", HttpServletResponse.SC_METHOD_NOT_ALLOWED);

		// Set the response MIME type (XML):
		response.setContentType("application/xml");

		// Set the character encoding:
		response.setCharacterEncoding(UWSToolBox.DEFAULT_CHAR_ENCODING);

		// Get the response stream:
		PrintWriter out = response.getWriter();

		// Write the XML document header:
		out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		if (xsltPath != null){
			out.print("<?xml-stylesheet type=\"text/xsl\" ");
			out.print(VOSerializer.formatAttribute("href", xsltPath));
			out.println("?>");
		}
		out.print("<vosi:capabilities xmlns:vosi=\"http://www.ivoa.net/xml/VOSICapabilities/v1.0\"");
		out.print(" xmlns:tr=\"http://www.ivoa.net/xml/TAPRegExt/v1.0\"");
		out.print(" xmlns:vr=\"http://www.ivoa.net/xml/VOResource/v1.0\"");
		out.print(" xmlns:vs=\"http://www.ivoa.net/xml/VODataService/v1.0\"");
		out.print(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
		out.println(" xsi:schemaLocation=\"http://www.ivoa.net/xml/VOSICapabilities/v1.0 http://www.ivoa.net/xml/VOSICapabilities/v1.0 http://www.ivoa.net/xml/TAPRegExt/v1.0 http://www.ivoa.net/xml/TAPRegExt/v1.0 http://www.ivoa.net/xml/VOResource/v1.0 http://www.ivoa.net/xml/VOResource/v1.0 http://www.ivoa.net/xml/VODataService/v1.0 http://www.ivoa.net/xml/VODataService/v1.0\">");

		// Write the full list of this TAP capabilities:
		out.print(tap.getCapability());

		// Write the capabilities of all VOSI resources:
		Iterator<TAPResource> it = tap.getResources();
		while(it.hasNext()){
			TAPResource res = it.next();
			if (res instanceof VOSIResource){
				String cap = ((VOSIResource)res).getCapability();
				if (cap != null){
					out.println();
					out.print(cap);
				}
			}
		}

		// Write the end of the XML document:
		out.println("\n</vosi:capabilities>");

		out.flush();

		return true;
	}

	/**
	 * Write the XML description of the given VOSI resource.
	 *
	 * @param res	Resource to describe in XML.
	 *
	 * @return	XML description of the given VOSI resource.
	 */
	public static final String getDefaultCapability(final VOSIResource res){
		return "\t<capability " + VOSerializer.formatAttribute("standardID", res.getStandardID()) + ">\n" + "\t\t<interface xsi:type=\"vs:ParamHTTP\" role=\"std\">\n" + "\t\t\t<accessURL use=\"full\"> " + ((res.getAccessURL() == null) ? "" : VOSerializer.formatText(res.getAccessURL())) + " </accessURL>\n" + "\t\t</interface>\n" + "\t</capability>";
	}

}
