package eu.dnetlib.data.objectstore.modular;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTPClient;

import com.google.common.base.Function;

import eu.dnetlib.data.objectstore.rmi.ObjectStoreFile;
import eu.dnetlib.data.objectstore.rmi.Protocols;



/**
 * The Class ObjectBroker is responsible to retrieve content from URL.
 */
public class ObjectBroker implements Function<String, ObjectStoreRecord> {
	private static final Log log = LogFactory.getLog(ObjectBroker.class);

	/** The protocol. */
	private Protocols protocol;

	/** The login. */
	private String login;

	/** The password. */
	private String password;

	/** The mime. */
	private String mime;

	/**
	 * Instantiates a new object broker.
	 * 
	 * @param protocol
	 *            the protocol
	 * @param login
	 *            the login
	 * @param password
	 *            the password
	 * @param mime
	 *            the mime
	 */
	public ObjectBroker(final Protocols protocol, final String login, final String password, final String mime) {
		this.protocol = protocol;
		this.login = login;
		this.password = password;
		this.mime = mime;
	}

	/**
	 * Gets the protocol.
	 * 
	 * @return the protocol
	 */
	public Protocols getProtocol() {
		return protocol;
	}

	/**
	 * Sets the protocol.
	 * 
	 * @param protocol
	 *            the new protocol
	 */
	public void setProtocol(final Protocols protocol) {
		this.protocol = protocol;
	}

	/**
	 * Gets the login.
	 * 
	 * @return the login
	 */
	public String getLogin() {
		return login;
	}

	/**
	 * Sets the login.
	 * 
	 * @param login
	 *            the new login
	 */
	public void setLogin(final String login) {
		this.login = login;
	}

	/**
	 * Gets the password.
	 * 
	 * @return the password
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * Sets the password.
	 * 
	 * @param password
	 *            the new password
	 */
	public void setPassword(final String password) {
		this.password = password;
	}

	/**
	 * Gets the mime.
	 * 
	 * @return the mime
	 */
	public String getMime() {
		return mime;
	}

	/**
	 * Sets the mime.
	 * 
	 * @param mime
	 *            the new mime
	 */
	public void setMime(final String mime) {
		this.mime = mime;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.common.base.Function#apply(java.lang.Object)
	 */
	@Override
	public ObjectStoreRecord apply(final String jsonInput) {
		if (jsonInput == null) return null;
		ObjectStoreRecord objectStorerecord = new ObjectStoreRecord();

		objectStorerecord.setFileMetadata(ObjectStoreFile.createObject(jsonInput));
		Protocols currentProtocol = (objectStorerecord.getFileMetadata().getAccessProtocol() == Protocols.None) ? protocol : objectStorerecord
				.getFileMetadata().getAccessProtocol();
		objectStorerecord.getFileMetadata().setAccessProtocol(currentProtocol);
		if ((objectStorerecord.getFileMetadata().getMimeType() == null) || (objectStorerecord.getFileMetadata().getMimeType().length() == 0)) {
			objectStorerecord.getFileMetadata().setMimeType(mime);
		}

		switch (currentProtocol) {
		case FTP:
			FTPClient client = new FTPClient();
			try {
				URI uri = new URI(objectStorerecord.getFileMetadata().getURI());
				client.connect(uri.getHost());
				if ((objectStorerecord.getFileMetadata().getUsernameAuth() != null) && (objectStorerecord.getFileMetadata().getUsernameAuth().length() > 0)) {
					client.login(objectStorerecord.getFileMetadata().getUsernameAuth(), objectStorerecord.getFileMetadata().getPasswordAuth());
				} else {
					client.login("ftp", "a@a");

				}

				final InputStream stream = client.retrieveFileStream(uri.getPath());
				objectStorerecord.setInputStream(stream);
				return objectStorerecord;

			} catch (URISyntaxException e2) {
				log.error(e2);
				return null;
			} catch (SocketException e) {
				log.error(e);
			} catch (IOException e) {
				log.error(e);
				return null;
			}

		case HTTP:
			try {
				HttpURLConnection conn = (HttpURLConnection) new URL(objectStorerecord.getFileMetadata().getURI()).openConnection();
				InputStream in;
				int http_status;
				try {

					http_status = conn.getResponseCode();

					if ((http_status / 100) == 3) {
						String newURL = conn.getHeaderField("Location");
						conn.disconnect();
						conn = (HttpURLConnection) new URL(newURL).openConnection();
						http_status = conn.getResponseCode();
						if ((http_status / 100) != 2) return null;
					}
					in = conn.getInputStream();
					objectStorerecord.setInputStream(in);
					return objectStorerecord;
				} catch (Exception e) {
					log.error(e);
					return null;
				}
			} catch (MalformedURLException e1) {
				log.error(e1);
				return null;
			} catch (IOException e1) {
				log.error(e1);
				return null;
			}

		case File_System:
			File f = new File(objectStorerecord.getFileMetadata().getURI());
			try {
				InputStream myiInputStream = new FileInputStream(f);
				objectStorerecord.setInputStream(myiInputStream);
				return objectStorerecord;
			} catch (FileNotFoundException e) {
				try {
					Thread.sleep(5000);
					InputStream myiInputStream = new FileInputStream(f);
					objectStorerecord.setInputStream(myiInputStream);
					return objectStorerecord;
				} catch (Exception e1) {
					log.error(e1);
					return null;
				}
			}
		default:
			break;
		}

		return null;

	}

}
