/*
 * Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 

/*
 * NetUtil.java
 */

package org.maxkey.crypto.cert;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Networking utilities.
 * 
 * @author Ville Skyttä
 */
public final class NetUtil
{
	/** Logger */
	private static final Logger _logger = LoggerFactory.getLogger(NetUtil.class);

	// TODO: make this configurable
	private static final int CONNECT_TIMEOUT = 10000;

	// TODO: make this configurable
	private static final int READ_TIMEOUT = 20000;

	/**
	 * Private to prevent construction.
	 */
	private NetUtil()
	{
		// Nothing to do
	}

	/**
	 * Open an input stream to a GET(-like) operation on an URL.
	 * 
	 * @param url The URL
	 * @return Input stream to the URL connection
	 * @throws IOException If an I/O error occurs
	 */
	public static InputStream openGetStream(URL url)
	    throws IOException
	{
		URLConnection conn = url.openConnection();

		conn.setConnectTimeout(CONNECT_TIMEOUT);
		conn.setReadTimeout(READ_TIMEOUT);

		// TODO: User-Agent?

		return conn.getInputStream();
	}

	/**
	 * Open an input stream to a POST(-like) operation on an URL.
	 * 
	 * @param url The URL
	 * @param content Content to POST
	 * @param contentType Content type
	 * @return Input stream to the URL connection
	 * @throws IOException If an I/O error occurs
	 */
	public static InputStream openPostStream(URL url, byte[] content, String contentType)
	    throws IOException
	{
		URLConnection conn = url.openConnection();
		conn.setDoOutput(true);

		conn.setConnectTimeout(CONNECT_TIMEOUT);
		conn.setReadTimeout(READ_TIMEOUT);

		// TODO: User-Agent?

		if (contentType != null)
		{
			conn.setRequestProperty("Content-Type", contentType);
		}

		conn.setRequestProperty("Content-Length", String.valueOf(content.length));

		OutputStream out = conn.getOutputStream();
		try
		{
			out.write(content);
		}
		finally
		{
			out.close();
		}

		return conn.getInputStream();
	}

	/**
	 * Download the given URL to a temporary local file. The temporary file is marked for deletion at exit.
	 * 
	 * @param url
	 * @return URL pointing to the temporary file, <code>url</code> itself if it's a file: one.
	 * @throws IOException
	 */
	public static URL download(URL url)
	    throws IOException
	{
		if ("file".equals(url.getProtocol()))
		{
			return url;
		}

		InputStream in = openGetStream(url);
		File tempFile = null;
		OutputStream out = null;

		try
		{
			tempFile = File.createTempFile("portecle", null);
			out = new BufferedOutputStream(new FileOutputStream(tempFile));
			byte[] buf = new byte[2048];
			int n;
			while ((n = in.read(buf)) != -1)
			{
				out.write(buf, 0, n);
			}
			out.flush();
			out.close();
		}
		catch (IOException e)
		{
			try
			{
				if (out != null)
				{
					out.close();
				}
			}
			finally
			{
				if (tempFile != null && !tempFile.delete())
				{
					_logger.info("Could not delete temporary file " + tempFile);
				}
			}
			throw e;
		}
		finally
		{
			in.close();
		}

		tempFile.deleteOnExit();

		return tempFile.toURI().toURL();
	}

	/**
	 * Creates a URL pointing to a URL, URI or a File object.
	 * 
	 * @param obj Object to create a URI to
	 * @return URL
	 * @throws ClassCastException if obj is not a supported object
	 * @throws MalformedURLException if converting obj to a URL fails
	 */
	public static URL toURL(Object obj)
	    throws MalformedURLException
	{
		if (obj instanceof File)
		{
			return ((File) obj).toURI().toURL();
		}
		else if (obj instanceof URI)
		{
			return ((URI) obj).toURL();
		}
		else
		{
			return (URL) obj;
		}
	}
}
