/* ======================================================================
   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.beans.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;
import java.io.*;
import java.util.*;

public class RemoteFileList extends javax.swing.JList
    implements java.awt.dnd.DragGestureListener, 
                java.awt.dnd.DragSourceListener,
                java.awt.dnd.DropTargetListener
	{
	RemoteFile base;

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

	public RemoteFileList( RemoteFile base )
		{
		this();
		setBase( base, false );
		}
	
	public void setFileUploader( FileUploader uploader )
		{
		this.uploader = uploader;
		}
		
    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 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( LocalFileSelection.localFileSelectionFlavor ) )
		        {
    			JOptionPane.showMessageDialog(null, "You can only drag files from the local file system here.", "Alert", JOptionPane.ERROR_MESSAGE); 
    		    dtde.rejectDrop();
		        return;
		        }

		    LocalFileSelection lflist =(LocalFileSelection)transferable.getTransferData( 
						LocalFileSelection.localFileSelectionFlavor );
    			
            if ( uploader == null )
                {
    			JOptionPane.showMessageDialog(null, "Can't find file uploader.", "Alert", JOptionPane.ERROR_MESSAGE); 
    		    dtde.rejectDrop();
		        return;
                }
                
			dtde.acceptDrop( DnDConstants.ACTION_COPY );
            uploader.transferFiles( base, lflist.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 )
    	{
        // This method is derived from interface java.awt.dnd.DragSourceListener
        // to do: code goes here
   	    }

    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();
            
	    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  )
        		{
        	    RemoteFileSelection selection = new RemoteFileSelection( sourcenode.file );
      			System.out.println( "Starting drag on: " + sourcenode.file.getHRef() );
      			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 void setBase( RemoteFile base, boolean show_deleted )
	{
	this.base = base;

	DefaultListModel model = new DefaultListModel();

	RemoteFile[] files = base.list();
	if ( files != null )
	    {
	    Arrays.sort( files, RemoteFileComparator.getInstance() );
	    for ( int i=0; i<files.length; i++ )
		{
		if ( show_deleted )
		    {
		    if ( !files[i].isDeleted() && !files[i].containsDeletedFiles() )
			continue;
		    }
		else
		    {
		    if ( files[i].isDeleted() )
			continue;
		    }
		model.addElement( new FileListNode( files[i] ) );
		}
	    }

	setModel( model );
	}

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

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

            RemoteFile f1 = (RemoteFile)o1;
            RemoteFile f2 = (RemoteFile)o2;
            
            if ( f1.isFolder() && f2.isFile() )
                return -1;

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

	// Inner class that represents a node in this file system tree
	protected static class FileListNode
	    implements Iconic
		{
		RemoteFile file;

        protected static Icon closedIcon = null;
        protected static Icon leafIcon = null;

		protected FileListNode( RemoteFile 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;
		    }
		}
		
    public RemoteFile[] getSelectedFiles()
        {
        Object[] olist = this.getSelectedValues();
        if ( olist == null )
            return null;
        RemoteFile[] flist = new RemoteFile[olist.length];
        for ( int i=0; i<olist.length; i++ )
            flist[i] = ((FileListNode)olist[i]).file;
        return flist;
        }

	}
