/**
 * Copyright 2008-2009 DRIVER PROJECT (Bielefeld University)
 * Original author: Marek Imialek <marek.imialek at uni-bielefeld.de>
 *
 * 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.
 */
package eu.dnetlib.data.utility.download.manager;

import java.io.File;
import java.util.List;

import org.apache.log4j.Logger;

import eu.dnetlib.data.utility.download.DownloadServiceException;
import eu.dnetlib.data.utility.download.dataprov.IDownloadDataProvider;
import eu.dnetlib.data.utility.download.manager.thread.DownloadProcessObserver;
import eu.dnetlib.data.utility.download.rs.iterator.IRSIterator;
import eu.dnetlib.data.utility.download.rs.iterator.ListResultSetIterator;

/**
 * The Class DownloadHandler.
 * 
 * @author <a href="mailto:marek.imialek at uni-bielefeld.de">Marek Imialek</a>
 */
public class DownloadManager {

	/** The Constant log. */
	protected static final Logger log = Logger.getLogger(DownloadManager.class);

	/** The default maximal storing time in seconds (24 hours). */
	private static long DEFAULT_MAX_STORING_TIME = 86400; 
	
	/** The download directory, the tmp directory is only used by junit tests, in the other cases this directory is overriten by proper property value. */
	private String downloadDirectory = "/tmp/download";
	
	/** The servlet directory. */
	private String servletDirectory = "/tmp/download/servlet";;

	/** The max storing time. */
	private long maxStoringTime;
	
	/** Data provider module. */
	private IDownloadDataProvider dataProvider;

	/** The max number downloads for host. */
	private int maxNumberDownloadsForHost;

	/**
	 * Init.
	 */
	public void init() {
		createDirectory(downloadDirectory);
		createDirectory(servletDirectory);
	}
	
	/**
	 * Method downloads all urls from the list. If the urlXPath
	 * parameter is set, method expects XMLs as input objects. In this case
	 * all XML objects should have the same structure and urlXPath
	 * parameter should point location of url in XML structure.
	 * 
	 * @param urlList the url list
	 * @param downloadProcessID the new download process id
	 * @param urlXPath location of url in XML structure if the objects are XMLs
	 * 
	 * @throws DownloadServiceException 	 */
	public void downloadList (List<String> urlList,
			String downloadProcessID, String urlXPath) {
	
		ListResultSetIterator listRSIterator = new ListResultSetIterator(urlList);
		
		DownloadProcessObserver dpo = new DownloadProcessObserver();
		dpo.setDataProvider(dataProvider);
		dpo.setDownloaProcessId(downloadProcessID);
		DownloadProcess dp = new DownloadProcess(listRSIterator, downloadProcessID, downloadDirectory, urlXPath);
		dp.setDataProvider(dataProvider);
		if (maxNumberDownloadsForHost != 0)
			dp.setMaxNumberDownloadsForHost(maxNumberDownloadsForHost);
		dp.addObserver(dpo);
		new Thread(dp).start();
		log.info("Downloading proccess send to the background, back to the client!");
	}
	
	/**
	 * Method downloads all urls from the list. If the urlXPath
	 * parameter is set, method expects XMLs as input objects. In this case
	 * all XML objects should have the same structure and urlXPath
	 * parameter should point location of url in XML structure.
	 * 
	 * @param rsIterator the rs iterator
	 * @param downloadProcessID the new download process id
	 * @param urlXPath location of url in XML structure if the objects are XMLs
	 * 
	 * @throws DownloadServiceException 	 */
	public void downloadRS (IRSIterator rsIterator,
			String downloadProcessID, String urlXPath) {
		
		rsIterator.iterate();
		DownloadProcessObserver dpo = new DownloadProcessObserver();
		dpo.setDataProvider(dataProvider);
		dpo.setDownloaProcessId(downloadProcessID);
		DownloadProcess dp = new DownloadProcess(rsIterator, downloadProcessID, downloadDirectory, urlXPath);
		dp.setDataProvider(dataProvider);
		if (maxNumberDownloadsForHost != 0)
			dp.setMaxNumberDownloadsForHost(maxNumberDownloadsForHost);
		dp.addObserver(dpo);
		new Thread(dp).start();
		log.info("Downloading proccess send to the background, back to the client!");
	}
	
	/**
	 * Performs cleanup operation.
	 */
	public void cleanup() {
		log.info("Cleaning download directory: "+ this.downloadDirectory);
		
		File mainDownloadDirectory = new File(this.downloadDirectory);
		if (mainDownloadDirectory.exists()) {
			String[] dirs = mainDownloadDirectory.list();
			
			if (this.maxStoringTime == 0)
				this.setMaxStoringTime(DEFAULT_MAX_STORING_TIME);
			
			if (dirs != null & dirs.length != 0) {
				for (int i=0; i<dirs.length; i++) {
					File dir = new File(this.downloadDirectory+"/"+dirs[i]);
					long modifiedTime = dir.lastModified();
					long currentTime = System.currentTimeMillis();
					long timeDiff = (currentTime - modifiedTime)/1000;
					
					if (timeDiff > this.maxStoringTime)
						deleteDirectory(dir);
				}
			}
		}
	}

	/**
	 * Method removes specified directory.
	 * 
	 * @param path the path
	 * 
	 * @return true, if delete directory
	 */
	private boolean deleteDirectory(File path) {
		if (path.exists()) {
			File[] files = path.listFiles();
			for (int i = 0; i < files.length; i++) {
				if (files[i].isDirectory()) {
					deleteDirectory(files[i]);
				} else {
					files[i].delete();
				}
			}
		}
		return (path.delete());
	}
	
	/**
	 * Creates the directory.
	 * 
	 * @param directoryPath the directory path
	 */
	private void createDirectory(String directoryPath) {
		
		File directoryFile = new File(directoryPath);
		log.debug("Crating download directory: " + 
				directoryFile.getAbsolutePath());
		if (!directoryFile.exists()) {
			if (!directoryFile.mkdirs())
				throw new RuntimeException("Could not create "
						+ "main storage directory, please check your "
						+ "access rights for the following location: "
						+ directoryFile.getAbsolutePath());
		} else {
			if (!directoryFile.canWrite()) 
				throw new RuntimeException("Can not write to the " +
						"directory, please check your " +
						"access rights for this location: "+
						directoryFile.getAbsolutePath());	
		}
	}
	
	/**
	 * Gets the download directory.
	 * 
	 * @return the download directory
	 */
	public String getDownloadDirectory() {
		return downloadDirectory;
	}

	/**
	 * Sets the download directory.
	 * 
	 * @param downloadDirectory the new download directory
	 */
	public void setDownloadDirectory(String downloadDirectory) {
		this.downloadDirectory = downloadDirectory;
	}
	
	/**
	 * Gets the download directory.
	 * 
	 * @return max storing time
	 */
	public long getMaxStoringTime() {
		return this.maxStoringTime;
	}

	/**
	 * Sets the maximal storing time.
	 * 
	 * @param maxStoringTime the new storing time
	 */
	public void setMaxStoringTime(long maxStoringTime) {
		this.maxStoringTime = maxStoringTime;
	}
	
	/**
	 * Gets the data provider.
	 * 
	 * @return the data provider
	 */
	public IDownloadDataProvider getDataProvider() {
		return dataProvider;
	}

	/**
	 * Sets the data provider.
	 * 
	 * @param dataProvider the new data provider
	 */
	public void setDataProvider(IDownloadDataProvider dataProvider) {
		this.dataProvider = dataProvider;
	}
	
	/**
	 * Gets the max number downloads for host.
	 * 
	 * @return maxNumberDownloadsForHost the new max number downloads for host
	 */
	public int getMaxNumberDownloadsForHost() {
		return this.maxNumberDownloadsForHost;
	}
	
	/**
	 * Sets the max number downloads for host.
	 * 
	 * @param maxNumberDownloadsForHost the new max number downloads for host
	 */
	public void setMaxNumberDownloadsForHost(int maxNumberDownloadsForHost) {
		this.maxNumberDownloadsForHost = maxNumberDownloadsForHost;
	}

	/**
	 * Gets the servlet directory.
	 * 
	 * @return the servletDirectory
	 */
	public String getServletDirectory() {
		return servletDirectory;
	}

	/**
	 * Sets the servlet directory.
	 * 
	 * @param servletDirectory the servletDirectory to set
	 */
	public void setServletDirectory(String servletDirectory) {
		this.servletDirectory = servletDirectory;
	}
	
}
