/* ======================================================================
The Bodington System Software License, Version 1.0
  
Copyright (c) 2001 The University of Leeds.  All rights reserved.
  
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

1.  Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2.  Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

3.  The end-user documentation included with the redistribution, if any,
must include the following acknowledgement:  "This product includes
software developed by the University of Leeds
(http://www.bodington.org/)."  Alternately, this acknowledgement may
appear in the software itself, if and wherever such third-party
acknowledgements normally appear.

4.  The names "Bodington", "Nathan Bodington", "Bodington System",
"Bodington Open Source Project", and "The University of Leeds" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
d.gardner@leeds.ac.uk.

5.  The name "Bodington" may not appear in the name of products derived
from this software without prior written permission of the University of
Leeds.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO,  TITLE,  THE IMPLIED WARRANTIES 
OF QUALITY  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO 
EVENT SHALL THE UNIVERSITY OF LEEDS OR ITS CONTRIBUTORS BE LIABLE FOR 
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
=========================================================

This software was originally created by the University of Leeds and may contain voluntary 
contributions from others.  For more information on the Bodington Open Source Project, please 
see http://bodington.org/

====================================================================== */

package org.bodington.applet.components;

import org.bodington.applet.*;
import org.bodington.applet.data.*;

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


public class RemoteFilePanel extends javax.swing.JPanel
	implements PropertyChangeListener, FileUploader, ClipboardOwner
	{
	JSplitPane split;
	RemoteFileTree tree;
	RemoteFileList list;
    
    JScrollPane tree_scroll, list_scroll;

    Clipboard clipboard;

    URL resource_url;
    
	public RemoteFilePanel( URL url, RemoteFile base )
		{
		resource_url = url;
		
	    setLayout( new GridLayout(1, 1) );

		tree = new RemoteFileTree( base );
		tree.setFileUploader( this );
		tree_scroll = new JScrollPane( tree );

		tree.addPropertyChangeListener( this );
		    
		    
		list = new RemoteFileList( base );
		list.setFileUploader( this );
		list_scroll = new JScrollPane( list );

		list.addPropertyChangeListener( this );


        split = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, tree_scroll, list_scroll );
        split.setDividerLocation( 250 );
        split.setOneTouchExpandable( true );
        add( split );
		}

	
    public void setClipboard( Clipboard clipboard )
        {
        this.clipboard = clipboard;
        }

    public void doNewFolder()
	{
	if ( tree.isSelectionAmongDeleted() )
	    {
	    JOptionPane.showMessageDialog(null, "You can't create folders in the deleted files area.", "Alert", JOptionPane.ERROR_MESSAGE); 
	    return;
	    }

	RemoteFile target = tree.getSelectedFolder();
	if ( target == null )
	    {
	    JOptionPane.showMessageDialog(null, "Select a target folder in the tree diagram before you create a new folder.", "Alert", JOptionPane.ERROR_MESSAGE); 
	    return;
	    }

        String name = "new_folder";
	RemoteFile test = target.findFile( name );
	for ( int i=1; test!=null; i++ )
	    test = target.findFile( name = "new_folder" + i );
	
	try
	    {
	    newFolder( target, name );
	    }
	catch ( Exception ex )
	    {
	    ex.printStackTrace();
	    JOptionPane.showMessageDialog(null, "An IO error occured trying to rename file.", "Alert", JOptionPane.ERROR_MESSAGE); 
	    }
	}

	public void doRename()
	    {
	    if ( tree.isSelectionAmongDeleted() )
	        {
		JOptionPane.showMessageDialog(null, "You can't rename files in the deleted files area.", "Alert", JOptionPane.ERROR_MESSAGE); 
		return;
	        }
	    
	    RemoteFile[] sel = list.getSelectedFiles();
	    if ( sel == null || sel.length != 1 )
	        {
			JOptionPane.showMessageDialog(null, "Select a single file or folder in the file list first.", "Alert", JOptionPane.ERROR_MESSAGE); 
			return;
	        }

       	String newname = JOptionPane.showInputDialog( sel[0].getName() ); 
       	
		try
		    {
		    renameFile( sel[0], newname );
		    }
		catch ( Exception ex )
		    {
		    ex.printStackTrace();
    		JOptionPane.showMessageDialog(null, "An IO error occured trying to rename file.", "Alert", JOptionPane.ERROR_MESSAGE); 
		    }
       	}

    public void doDelete()
	{
	if ( tree.isSelectionAmongDeleted() )
	    {
	    JOptionPane.showMessageDialog(null, "You can't delete files in the deleted files area.", "Alert", JOptionPane.ERROR_MESSAGE); 
	    return;
	    }

	RemoteFile[] sel = list.getSelectedFiles();
	if ( sel == null || sel.length < 1 )
	    {
	    JOptionPane.showMessageDialog(null, "Select a file or folder in the file list first.", "Alert", JOptionPane.ERROR_MESSAGE); 
	    return;
	    }
	
	if ( sel.length > 1 )
	    {
	    JOptionPane.showMessageDialog(null, "Select just one file or folder in the file list.", "Alert", JOptionPane.ERROR_MESSAGE); 
	    return;
	    }
	
	try
	    {
	    deleteFile( sel[0] );
	    }
	catch ( Exception ex )
	    {
	    ex.printStackTrace();
	    JOptionPane.showMessageDialog(null, "An IO error occured trying to delete the file.", "Alert", JOptionPane.ERROR_MESSAGE); 
	    }
	}

    public void doUndelete()
	{
	if ( !tree.isSelectionAmongDeleted() )
	    {
	    JOptionPane.showMessageDialog(null, "You can only undelete files in the deleted files area.", "Alert", JOptionPane.ERROR_MESSAGE); 
	    return;
	    }

	RemoteFile[] sel = list.getSelectedFiles();
	if ( sel == null || sel.length < 1 )
	    {
	    JOptionPane.showMessageDialog(null, "Select a file or folder in the file list first.", "Alert", JOptionPane.ERROR_MESSAGE); 
	    return;
	    }
	
	if ( sel.length > 1 )
	    {
	    JOptionPane.showMessageDialog(null, "Select just one file or folder in the file list.", "Alert", JOptionPane.ERROR_MESSAGE); 
	    return;
	    }
	
	boolean recurse=false;
	if ( sel[0].isFolder() )
	    {
	    int option = JOptionPane.showOptionDialog(
			    null, 
			    "Undelete all the contents of the folder?", 
			    "Undelete Option", 
			    JOptionPane.YES_NO_CANCEL_OPTION,
			    JOptionPane.QUESTION_MESSAGE,
			    null,
			    null,
			    null ); 
	    if ( option == JOptionPane.CLOSED_OPTION || option == JOptionPane.CANCEL_OPTION )
		return;
	    recurse = option == JOptionPane.YES_OPTION;
	    }
	
	try
	    {
	    undeleteFile( sel[0], recurse );
	    }
	catch ( Exception ex )
	    {
	    ex.printStackTrace();
	    JOptionPane.showMessageDialog(null, "An IO error occured trying to undelete the file.", "Alert", JOptionPane.ERROR_MESSAGE); 
	    }
	}

	public void doOpenTextFile()
	    {
	    if ( tree.isSelectionAmongDeleted() )
	        {
		JOptionPane.showMessageDialog(null, "You can't open files in the deleted files area.", "Alert", JOptionPane.ERROR_MESSAGE); 
		return;
	        }
		
	    RemoteFile[] sel = list.getSelectedFiles();
	    if ( sel == null || sel.length != 1 || !sel[0].isFile() )
	        {
			JOptionPane.showMessageDialog(null, "Select a single file in the file list first.", "Alert", JOptionPane.ERROR_MESSAGE); 
			return;
	        }

	    // find the desktop
	    Component component = this;
	    while ( component!=null && !(component instanceof BodingtonDesktopPane) )
	        component = component.getParent();
	        
	    if ( component == null )
	        {
			JOptionPane.showMessageDialog(null, "Can't find a Java Desktop to open a new window in.", "Alert", JOptionPane.ERROR_MESSAGE); 
			return;
	        }
	    
	    BodingtonDesktopPane desktop = (BodingtonDesktopPane)component;
	    TextEditorFrame frame = new TextEditorFrame( resource_url, sel[0] );
	    frame.setLocation( 20, 20 );
	    frame.setSize( 400, 200 );
	    desktop.add( frame );
            frame.setVisible( true );
            frame.doRefresh();
	    }
	    
    public boolean doNewFile( String mime_type )
	    {
	    if ( tree.isSelectionAmongDeleted() )
	        {
		JOptionPane.showMessageDialog(null, "You can't create new files in the deleted files area.", "Alert", JOptionPane.ERROR_MESSAGE); 
		return false;
	        }
	    
	    RemoteFile target = tree.getSelectedFolder();
	    if ( target == null )
	        {
			JOptionPane.showMessageDialog(null, "Select a target folder in the tree diagram before you paste.", "Alert", JOptionPane.ERROR_MESSAGE); 
			return false;
	        }
	        
	    String suffix, name;
        if ( mime_type.equals( "text/html" ) )
            suffix = ".html";
        else
            suffix = ".txt";

        name = "new" + suffix;
	    RemoteFile test = target.findFile( name );
	    for ( int i=1; test!=null; i++ )
	        test = target.findFile( name = "new" + i + suffix );
	        
		try
            {		    
            File temp;
            temp = File.createTempFile( "temp", suffix );
            
            PrintWriter writer = new PrintWriter( 
                                 new OutputStreamWriter(
                                 new FileOutputStream( temp ), "UTF-8" ) );

            if ( mime_type.equals( "text/html" ) )
                {
                writer.println( "<HTML>" );
                writer.println( "<HEAD>" );
                writer.println( "<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">" );
                writer.println( "<LINK HREF=\"bs_template_user.css\" TYPE=\"text/css\" REL=\"STYLESHEET\">" );
                writer.println( "<TITLE>Page Title Goes Here</TITLE>" );
                writer.println( "</HEAD>" );
                writer.println( "<BODY>" );
                writer.println( "</BODY>" );
                writer.println( "</HTML>" );
                }

            writer.println();
            writer.flush();
            writer.close();
                
   		    transferFile( target, temp, name );
            
            temp.delete();
		    }
		catch ( Exception ex )
		    {
		    ex.printStackTrace();
    		JOptionPane.showMessageDialog( null, "Technical problem transferring files.", "Alert", JOptionPane.ERROR_MESSAGE ); 
		    return false;
		    }

   		JOptionPane.showMessageDialog( null, "New File Created.", "Alert", JOptionPane.ERROR_MESSAGE ); 
		
    	return true;
	    }
	    

	public void doFileCopy()
	    {
	    if ( tree.isSelectionAmongDeleted() )
	        {
		JOptionPane.showMessageDialog(null, "You can't copy files in the deleted files area.", "Alert", JOptionPane.ERROR_MESSAGE); 
		return;
	        }
	    
	    if ( clipboard==null )
	        {
			JOptionPane.showMessageDialog(null, "No clipboard is available.", "Alert", JOptionPane.ERROR_MESSAGE); 
			return;
			}
	        
	    RemoteFile[] flist = list.getSelectedFiles();
	    if ( flist==null || flist.length == 0 )
	        {
			JOptionPane.showMessageDialog(null, "Select one or more files in the list box to copy it.", "Alert", JOptionPane.ERROR_MESSAGE); 
	        return;
	        }
	        
        RemoteFileSelection transfer = new RemoteFileSelection( flist );
     
        clipboard.setContents( transfer, this );
	    }
	    
    public boolean doFilePaste()
	    {
	    if ( tree.isSelectionAmongDeleted() )
	        {
		JOptionPane.showMessageDialog(null, "You can't paste files in the deleted files area.", "Alert", JOptionPane.ERROR_MESSAGE); 
		return false;
	        }
	    
	    if ( clipboard==null )
	        {
			JOptionPane.showMessageDialog(null, "No clipboard is available.", "Alert", JOptionPane.ERROR_MESSAGE); 
			return false;
			}
	    
	    Transferable data = clipboard.getContents( this );
	    if ( data == null )
	        {
			JOptionPane.showMessageDialog(null, "The clipboard is empty.", "Alert", JOptionPane.ERROR_MESSAGE); 
			return false;
			}
			
	    if ( !data.isDataFlavorSupported( LocalFileSelection.localFileSelectionFlavor ) )
	        {
			JOptionPane.showMessageDialog(null, "The clipboard doesn't contain files.", "Alert", JOptionPane.ERROR_MESSAGE); 
			return false;
	        }

	    RemoteFile target = tree.getSelectedFolder();
	    if ( target == null )
	        {
			JOptionPane.showMessageDialog(null, "Select a target folder in the tree diagram before you paste.", "Alert", JOptionPane.ERROR_MESSAGE); 
			return false;
	        }
	        
        StringBuffer message = new StringBuffer();   
        
        LocalFileSelection selection;
        File[] flist;
        try
            {
            selection = (LocalFileSelection)data.getTransferData( LocalFileSelection.localFileSelectionFlavor );
            flist = selection.getFileList();
            }
        catch ( Exception ex )
            {
            ex.printStackTrace();
			JOptionPane.showMessageDialog(null, "Technical problem transferring data.", "Alert", JOptionPane.ERROR_MESSAGE); 
			return false;
            }
         
        for ( int i=0; i<flist.length; i++ )
            {
            if ( i>0 )
                message.append( ", " );
            message.append( flist[i].getAbsolutePath() );
            }
            
		try
            {		    
		    transferFiles( target, flist, true );
		    }
		catch ( Exception ex )
		    {
		    ex.printStackTrace();
    		JOptionPane.showMessageDialog( null, "Technical problem initiating file transfer.", "Alert", JOptionPane.ERROR_MESSAGE ); 
		    return false;
		    }

		
	    return true;
	    }
	    
	public void doFileProperties()
	    {
	    /*
	    File[] flist = list.getSelectedFiles();
	    if ( flist==null || flist.length == 0 )
	        {
			JOptionPane.showMessageDialog(null, "Select one file in the list box to view its properties.", "Alert", JOptionPane.ERROR_MESSAGE); 
	        return;
	        }
	        
	    if ( flist.length > 1 )
	        {
			JOptionPane.showMessageDialog(null, "Select just one files in the list box to view its properties.", "Alert", JOptionPane.ERROR_MESSAGE); 
	        return;
	        }

		JOptionPane.showMessageDialog(null, "Properties functionality not implemented.", "Alert", JOptionPane.ERROR_MESSAGE); 
		*/
	    }

    public void transferFile( RemoteFile destination, File source, String name )
		throws IOException, MalformedURLException
		{
		System.out.println( "Uploading to: " + destination.getHRef() );

		if ( !destination.isFolder() )
		    throw new IOException( "Can't upload into a file." );

		TransferLocalFileDialog dialog = new TransferLocalFileDialog( BodingtonDesktopPane.findInstance( this ) );
		dialog.setProgressListener(  BodingtonDesktopPane.findInstance( this ).getRemoteFileFrame() );
		dialog.setVisible( true );

		Vector list = new Vector();
		File[] sourcelist = new File[1];
		String[] names = new String[1];
		sourcelist[0] = source;
		names[0] = name;
		listTransferFiles( list, destination.getPath(), sourcelist, names, destination.getUrlCharEncoding(), false );
		
		TransferLocalFileItem[] array = new TransferLocalFileItem[list.size()];
		for ( int i=0; i<list.size(); i++ )
		    array[i] = (TransferLocalFileItem)list.elementAt( i );
		
		if ( !dialog.isCancelled() )
		    dialog.transfer( array );
		}
		
	public void transferFiles( RemoteFile destination, File[] source, boolean recursive )
		throws IOException, MalformedURLException
		{
		System.out.println( "Uploading to: " + destination.getHRef() );

		if ( !destination.isFolder() )
		    throw new IOException( "Can't upload into a file." );

		TransferLocalFileDialog dialog = new TransferLocalFileDialog( BodingtonDesktopPane.findInstance( this ) );
		dialog.setProgressListener( BodingtonDesktopPane.findInstance( this ).getRemoteFileFrame() );
		dialog.setVisible( true );

		Vector list = new Vector();

		listTransferFiles( list, destination.getPath(), source, null, destination.getUrlCharEncoding(), recursive );
		
		TransferLocalFileItem[] array = new TransferLocalFileItem[list.size()];
		for ( int i=0; i<list.size(); i++ )
		    array[i] = (TransferLocalFileItem)list.elementAt( i );
		
		if ( !dialog.isCancelled() )
		    dialog.transfer( array );
		}
		
	private void listTransferFiles( Vector list, String destination, File[] source, String[] names, String url_char_encoding, boolean recursive )
		throws IOException, MalformedURLException
		{
		System.out.println( "Uploading to: " + destination );
		    
		// transfer the file first, if it is a file
		File[] sub_listing;
		String dest;
		String sub_dest;
		String name;
		TransferLocalFileItem item;
		
		for ( int i=0; i<source.length; i++ )
		    {
		    if ( source[i].isFile() )
			    {
			    dest = resource_url.toExternalForm() +
			            destination;
			    if ( !destination.endsWith( "/" ) )
			        dest = dest + "/";
			    dest = dest + "bs_virtual_uploadconfirm.txt";
			            
			    URL publish_page_url = new URL(	dest );
    		    
			    System.out.println( "Uploading" );
			    System.out.println( source[i].getAbsolutePath() );
			    System.out.println( "to" );
			    System.out.println( publish_page_url.toExternalForm() );
    			
			    if ( names!=null && names[i]!=null )
				name = names[i];
			    else
				name = source[i].getName();
    			    
			    item = new TransferLocalFileItem();
			    item.file = source[i];
			    item.name = name;
			    item.url = publish_page_url;
			    // adds the file to the list of files to transfer
			    list.addElement( item );
			    }
			}
			
		// transfer contained files if there are any
		if ( recursive )
		    {
		    for ( int i=0; i<source.length; i++ )
		        {
		        if ( !source[i].isFile() )
		            {
		            sub_listing = source[i].listFiles();
		            sub_dest = destination + 
				org.bodington.util.URLEncoder.encode( source[i].getName(), url_char_encoding ) + "/";
    			    listTransferFiles( list, sub_dest, sub_listing, null, url_char_encoding, recursive );
    			    }
    			}
			}

		}

    
    private void newFolder( RemoteFile file, String name )
	throws IOException, MalformedURLException
	{
	String dest;
	TransferFormDataDialog dialog=null;

	dest = resource_url.toExternalForm() +
		    file.getPath();
	if ( !dest.endsWith( "/" ) )
		dest = dest + "/";
	dest = dest + "bs_virtual_createfolderconfirm.txt";

	URL url = new URL( dest );

	dialog = new TransferFormDataDialog( BodingtonDesktopPane.findInstance( this ) );
	dialog.setProgressListener(  BodingtonDesktopPane.findInstance( this ).getRemoteFileFrame() );
	dialog.setVisible( true );
	String[] names = new String[1];
	String[] values = new String[1];
	names[0]="folder_name";
	values[0]=name;
	dialog.transfer( names, values, url );
	}
	
    private void renameFile( RemoteFile file, String to )
	throws IOException, MalformedURLException
	{
	String dest;
	TransferFormDataDialog dialog=null;

	dest = resource_url.toExternalForm() +
		    file.getPath();
	if ( !dest.endsWith( "/" ) )
		dest = dest + "/";
	dest = dest + "bs_virtual_renameconfirm.txt";

	URL rename_url = new URL(	dest );

	System.out.println( rename_url.toExternalForm() );

	dialog = new TransferFormDataDialog( BodingtonDesktopPane.findInstance( this ) );
	dialog.setProgressListener(  BodingtonDesktopPane.findInstance( this ).getRemoteFileFrame() );
	dialog.setVisible( true );
	String[] names = new String[1];
	String[] values = new String[1];
	names[0]="file_name";
	values[0]=to;
	dialog.transfer( names, values, rename_url );
	}

	private void deleteFile( RemoteFile file )
		throws IOException, MalformedURLException
		{
		String dest;
		TransferFormDataDialog dialog=null;
		
		dest = resource_url.toExternalForm() +
			    file.getPath();
		if ( !dest.endsWith( "/" ) )
			dest = dest + "/";
		dest = dest + "bs_virtual_deleteconfirm.txt";
			            
		URL url = new URL( dest );
    		    
		System.out.println( url.toExternalForm() );
    			
		dialog = new TransferFormDataDialog( BodingtonDesktopPane.findInstance( this ) );
		dialog.setProgressListener(  BodingtonDesktopPane.findInstance( this ).getRemoteFileFrame() );
		dialog.setVisible( true );
		String[] names = new String[0];
		String[] values = new String[0];
		dialog.transfer( names, values, url );
		}

        
	private void undeleteFile( RemoteFile file, boolean recurse )
		throws IOException, MalformedURLException
		{
		String dest;
		TransferFormDataDialog dialog=null;
		
		dest = resource_url.toExternalForm() +
			    file.getPath();
		if ( !dest.endsWith( "/" ) )
			dest = dest + "/";
		dest = dest + "bs_virtual_undeleteconfirm.txt";
			            
		URL url = new URL( dest );
    		    
		System.out.println( url.toExternalForm() );
    			
		dialog = new TransferFormDataDialog( BodingtonDesktopPane.findInstance( this ) );
		dialog.setProgressListener(  BodingtonDesktopPane.findInstance( this ).getRemoteFileFrame() );
		dialog.setVisible( true );
		String[] names = new String[recurse?1:0];
		String[] values = new String[recurse?1:0];
		if ( recurse )
		    {
		    names[0]="recurse";
		    values[0]="true";
		    }
		dialog.transfer( names, values, url );
		}
		
	public void propertyChange(PropertyChangeEvent evt)
		{
		if ( evt.getPropertyName().equalsIgnoreCase( "leadSelectionPath" ) )
			{
			list.setBase( tree.getSelectedFolder(), tree.isSelectionAmongDeleted() );
			}
		}

    public void lostOwnership( Clipboard clipboard, Transferable contents )
        {
        // don't care!
        }

	}
