/* ======================================================================
   Parts Copyright 2006 University of Leeds, Oxford University, University of the Highlands and Islands.

   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 org.bodington.applet.components;

import org.bodington.applet.data.*;

import javax.swing.*;
import java.awt.dnd.*;
import java.awt.event.*;
import java.awt.datatransfer.*;
import java.beans.*;
import java.awt.*;
import java.io.*;
import java.util.*;

public class LocalFileList extends javax.swing.JList
    implements java.awt.dnd.DragGestureListener, 
                java.awt.dnd.DragSourceListener,
                java.awt.dnd.DropTargetListener
	{
	File path;
	DragSource dragSource = null;
    DropTarget dropTarget = null;

	FileDownloader downloader;

	public LocalFileList()
		{
		setCellRenderer( new FileListCellRenderer() );
		//dropTarget = new DropTarget( this, this );
		//dragSource = new DragSource();
		//dragSource.createDefaultDragGestureRecognizer( this, DnDConstants.ACTION_COPY_OR_MOVE, this);
		}

	public LocalFileList( File path )
		{
		this();
		setDirectory( path );
		}
		
	public void setFileDownloader( FileDownloader downloader )
		{
		this.downloader = downloader;
		}
		
    protected void processFocusEvent( FocusEvent e )
        {
        super.processFocusEvent( e );
        // background of selected items changes
        // when focus is lost so we need to get
        // the list items to redraw
        repaint();
        }
		
	public void setDirectory( File path )
		{
		this.path = path;

		DefaultListModel model = new DefaultListModel();

		if ( path != null )
			{
			File[] files = path.listFiles();
			if ( files!=null )
			    {
                Arrays.sort( files, LocalFileComparator.getInstance() );
			    for ( int i=0; i<files.length; i++ )
				    {
				    //if ( files[i].isFile() )
					model.addElement( new FileListNode( files[i] ) );
				    }
				}
			}

		setModel( model );
		}

    public File[] getSelectedFiles()
        {
        Object[] olist = this.getSelectedValues();
        if ( olist == null )
            return null;
        File[] flist = new File[olist.length];
        for ( int i=0; i<olist.length; i++ )
            flist[i] = ((FileListNode)olist[i]).file;
        return flist;
        }


    public void dragEnter( DropTargetDragEvent dtde )
   	    {
        System.out.println( "public void dragEnter(DropTargetDragEvent dtde)" );
        if ( dtde.getSource() == this )
        	dtde.rejectDrag();
        else
        	dtde.acceptDrag( DnDConstants.ACTION_COPY );
   	    }

    public void dragExit( DropTargetEvent dte )
   	    {
   	    }

    public void drop( DropTargetDropEvent dtde )
        {
	    System.out.println( "Drop requested" );

	    try
		    {
		    Transferable transferable = dtde.getTransferable();

		    if ( !transferable.isDataFlavorSupported( RemoteFileSelection.remoteFileSelectionFlavor ) )
		        {
    			JOptionPane.showMessageDialog(null, "You can only drag files from the remote file system here.", "Alert", JOptionPane.ERROR_MESSAGE); 
    		    dtde.rejectDrop();
		        return;
		        }

		    RemoteFileSelection rflist =(RemoteFileSelection)transferable.getTransferData( 
						RemoteFileSelection.remoteFileSelectionFlavor );
    			
            if ( downloader == null )
                {
    			JOptionPane.showMessageDialog(null, "Can't find file downloader.", "Alert", JOptionPane.ERROR_MESSAGE); 
    		    dtde.rejectDrop();
		        return;
                }
                
			dtde.acceptDrop( DnDConstants.ACTION_COPY );
            downloader.transferFiles( path, rflist.getFileList(), true );
		    }
	    catch (IOException exception)
		    {
		    exception.printStackTrace();
		    System.err.println( "Exception" + exception.getMessage());
		    dtde.rejectDrop();
		    } 
	    catch (UnsupportedFlavorException ufException )
		    {
		    ufException.printStackTrace();
		    System.err.println( "Exception" + ufException.getMessage());
		    dtde.rejectDrop();
		    }   
        }

    public void dragOver( DropTargetDragEvent dtde )
        {
        dtde.acceptDrag(DnDConstants.ACTION_COPY);
        }

    public void dropActionChanged( DropTargetDragEvent dtde )
        {
        // This method is derived from interface java.awt.dnd.DropTargetListener
        // to do: code goes here
        }


    public void dragDropEnd( DragSourceDropEvent dsde )
    	{
    	System.out.println( "LocalFileList.dragDropEnd" );
   	    }

    public void dragEnter( DragSourceDragEvent dsde )
   	    {
        // This method is derived from interface java.awt.dnd.DragSourceListener
        // to do: code goes here
   	    }

    public void dragExit( DragSourceEvent dse )
   	    {
        // This method is derived from interface java.awt.dnd.DragSourceListener
        // to do: code goes here
   	    }

    public void dragGestureRecognized( DragGestureEvent event )
    	{
    	// what selection are made at this time?
    	int[] ilist = getSelectedIndices();
    	System.out.println( "LocalFileList has " + ilist.length + " selections at start of drag." );
    	for ( int i=0; i<ilist.length; i++ )
            System.out.println( "Selection index: " + ilist[i] );    	    
            
	    Point p = event.getDragOrigin();
	    int i = locationToIndex( p );
	    
	    // if not on a list item forget it
	    if ( i<0 )
	    	return;

		FileListNode sourcenode = (FileListNode)getModel().getElementAt( i );
	 
    	if ( sourcenode != null )
	   		{
    		if ( sourcenode.file != null  )
        		{
        		if ( sourcenode.file.exists() )
         			{
            	    LocalFileSelection selection = new LocalFileSelection( sourcenode.file );
         			System.out.println( "Starting drag on: " + sourcenode.file.getAbsolutePath() );
         			dragSource.startDrag(event, DragSource.DefaultMoveDrop, selection, this);
         			}
        		}
   			}
		else
	   		{
    		System.out.println( "nothing was selected");   
   			}
    	}

    public void dragOver( DragSourceDragEvent dsde )
        {
        // This method is derived from interface java.awt.dnd.DragSourceListener
        // to do: code goes here
        }

    public void dropActionChanged( DragSourceDragEvent dsde )
        {
        // This method is derived from interface java.awt.dnd.DragSourceListener
        // to do: code goes here
        } 


    public static class LocalFileComparator
        implements Comparator
        {
        private static LocalFileComparator instance = 
            new LocalFileComparator();
            
        public static LocalFileComparator getInstance()
            {
            return instance;
            }

        public int compare( Object o1, Object o2 )
            {
            if ( !(o1 instanceof File) )
                return 0;
            if ( !(o2 instanceof File) )
                return 0;

            File f1 = (File)o1;
            File f2 = (File)o2;
            
            if ( f1.isDirectory() && f2.isFile() )
                return -1;

            if ( f2.isDirectory() && f1.isFile() )
                return 1;
            
            String s1 = f1.getName();
            String s2 = f2.getName();
            
            
            return String.CASE_INSENSITIVE_ORDER.compare( s1, s2 );
            }
        
        public boolean equals( Object obj )
            {
            return obj instanceof LocalFileComparator;
            }
        
        }




	// Inner class that represents a node in this file system tree
	protected static class FileListNode
	    implements Iconic
		{
        protected static Icon closedIcon = null;
        protected static Icon leafIcon = null;
    
		File file;
		protected FileListNode( File f )
			{
			file = f;
            if ( closedIcon == null )
                closedIcon = UIManager.getIcon("Tree.closedIcon");
            if ( leafIcon == null )
                leafIcon = UIManager.getIcon("Tree.leafIcon");
			}

		public String toString()
			{
			return file.getName();
			}
		
		public Icon getIcon()
		    {
		    if ( file.isFile() )
		        return leafIcon;
		    return closedIcon;
		    }
		}
	}
