/* ======================================================================
   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.*;
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 occurred 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 occurred 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 occurred 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 occurred 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!
        }

	}
