package tim.prune.fileutils;

import java.awt.datatransfer.DataFlavor;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import javax.swing.TransferHandler;

import tim.prune.App;

/**
 * Class to listen for drag/drop events and react to dropping files on to the application
 */
public class FileDropHandler extends TransferHandler
{
	/** App object for passing results back to */
	private final App _app;

	/** Fixed flavour in case the java file list flavour isn't available */
	private static DataFlavor _uriListFlavour = null;

	/** Static block to initialise the list flavour */
	static
	{
		try {
			_uriListFlavour = new DataFlavor("text/uri-list;class=java.lang.String");
		} catch (ClassNotFoundException nfe) {}
	}


	/**
	 * Constructor
	 * @param inApp App object to pass results of drop back to
	 */
	public FileDropHandler(App inApp) {
		_app = inApp;
	}

	/**
	 * Check if the object being dragged can be accepted
	 * @param inSupport object to check
	 */
	public boolean canImport(TransferSupport inSupport)
	{
		boolean retval = inSupport.isDataFlavorSupported(DataFlavor.javaFileListFlavor)
			|| inSupport.isDataFlavorSupported(_uriListFlavour);
		// Modify icon to show a copy, not a move (+ icon on cursor)
		if (retval) {
			inSupport.setDropAction(COPY);
		}
		return retval;
	}

	/**
	 * Accept the incoming data and pass it on to the App
	 * @param inSupport contents of drop
	 */
	public boolean importData(TransferSupport inSupport)
	{
		if (!canImport(inSupport)) {return false;} // not allowed

		boolean success = false;
		ArrayList<File> dataFiles = new ArrayList<>();

		// Try a java file list flavour first
		try
		{
			@SuppressWarnings("unchecked")
			List<File> fileList = (List<File>) inSupport.getTransferable().getTransferData(
				DataFlavor.javaFileListFlavor);
			success = true;

			for (File f : fileList)
			{
				if (f != null && f.exists())
				{
					if (f.isDirectory()) {
						addDirectoryToList(f, dataFiles);
					}
					else if (f.isFile()) {
						dataFiles.add(f);
					}
				}
			}
		} catch (Exception e) {}  // exception caught, probably missing a javafilelist flavour - just continue

		// If that didn't work, try a list of strings instead
		if (!success)
		{
			try
			{
				String pathList = inSupport.getTransferable().getTransferData(_uriListFlavour).toString();

				for (String s : pathList.split("[\n\r]+"))
				{
					if (s != null && !s.equals(""))
					{
						File f = new File(new URI(s));
						if (f.exists())
						{
							if (f.isDirectory()) {
								addDirectoryToList(f, dataFiles);
							}
							else if (f.isFile()) {
								dataFiles.add(f);
							}
						}
					}
				}
			} catch (Exception e) {
				System.err.println("exception: " + e.getClass().getName() + " - " + e.getMessage());
				return false;
			}
		}

		// Pass files back to app
		if (!dataFiles.isEmpty()) {
			_app.loadDataFiles(dataFiles);
		}
		return true;
	}


	/**
	 * Recursively-called method to add files from the given directory (and its subdirectories)
	 * to the given list of files
	 * @param inDir directory to add
	 * @param inList file list to append to
	 */
	private void addDirectoryToList(File inDir, List<File> inList)
	{
		if (inDir != null && inDir.exists() && inDir.canRead() && inDir.isDirectory() && inList != null)
		{
			for (File file : FileList.filesIn(inDir))
			{
				if (file != null && file.exists() && file.canRead())
				{
					if (file.isFile())
					{
						// Add the found file to the list (if it's not in there already)
						if (!inList.contains(file)) {
							inList.add(file);
						}
					}
					else if (file.isDirectory())
					{
						// Recursively add the files from subdirectories
						addDirectoryToList(file, inList);
					}
				}
			}
		}
	}
}
