/* ======================================================================
   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 javax.swing.*;
import javax.swing.tree.*;

import java.awt.dnd.*;
import java.awt.event.*;
import java.awt.datatransfer.*;
import java.beans.*;
import java.awt.*;
import java.io.*;
import java.net.URL;
import org.w3c.dom.*;

import org.bodington.server.ims.*;


public class PackageTree extends javax.swing.JTree 
	implements DragSourceListener, DropTargetListener, DragGestureListener
	{
	org.bodington.server.ims.Package ims_package;
	
  /**
   * enables this component to be a dropTarget
   */

  DropTarget dropTarget = null;

  /**
   * enables this component to be a Drag Source
   */
  DragSource dragSource = null;



	public PackageTree( org.bodington.server.ims.Package p )
		{
		ims_package = p;
		
		dropTarget = new DropTarget (this, this);
		dragSource = new DragSource();
		dragSource.createDefaultDragGestureRecognizer( this, DnDConstants.ACTION_COPY_OR_MOVE, this);

		//{{REGISTER_LISTENERS
		//}}

      setModel( ims_package );   
      setRootVisible( false );
      setShowsRootHandles( true );
		}

	//{{DECLARE_CONTROLS
	//}}

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

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

    public void dragEnter(DropTargetDragEvent event)
        {
        System.out.println( "public void dragEnter(DropTargetDragEvent dtde)" );
        event.acceptDrag( DnDConstants.ACTION_COPY );
        }

    public void dragExit(DropTargetEvent dte)
    {
        // This method is derived from interface java.awt.dnd.DropTargetListener
        // 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 dragOver(DropTargetDragEvent dtde)
        {
        dtde.acceptDrag(DnDConstants.ACTION_COPY);
        }

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

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

	try
		{
		Transferable transferable = event.getTransferable();
		Point p = event.getLocation();
		TreePath targetpath;
		Rectangle targetbox;
		PackageNode targetnode, siblingnode;
		DefaultTreeModel model = (DefaultTreeModel)getModel();
		int position;


		
		// we accept only Strings      
		if (transferable.isDataFlavorSupported( PackageNode.packageNodeFlavor ) )
			{
			System.out.println( "String dropped" );
			targetpath = getPathForLocation( p.x, p.y );
			targetbox = getPathBounds( targetpath );

		    
			if ( targetpath != null )
				{
			    int margin = targetbox.height/10;
			    if ( margin < 5 ) margin = 5;
			    if ( margin > targetbox.height/2 ) margin = targetbox.height/2;
    			
			    if ( (targetbox.y + targetbox.height - p.y) <= margin )
			        {
				    siblingnode = (PackageNode)targetpath.getLastPathComponent();
				    if ( siblingnode.getChildCount()>0 )
				        {
				        targetnode = siblingnode;
				        position = 0;
				        }
				    else
				        {
				        targetnode = (PackageNode)siblingnode.getParent();
				        position = targetnode.getIndex( siblingnode ) + 1;
				        }
			        System.out.println( "Near bottom of target" );
			        }
			    else if ( (p.y - targetbox.y) <= margin )
			        {
				    siblingnode = (PackageNode)targetpath.getLastPathComponent();
				    targetnode = (PackageNode)siblingnode.getParent();
				    position = targetnode.getIndex( siblingnode );
			        System.out.println( "Near top of target" );
			        }
			    else
			        {
				    targetnode = (PackageNode)targetpath.getLastPathComponent();
				    position = targetnode.getChildCount();
				    }

				System.out.println( "Dropped on: " + targetnode.toString() );

				PackageNode node = (PackageNode)transferable.getTransferData( PackageNode.packageNodeFlavor );
				System.out.println( node.toString() );

				if ( targetnode.canDrop( node ) )
					{
					event.acceptDrop(DnDConstants.ACTION_COPY);
					try
						{
						System.out.println( "Dropping now..." );
						targetnode.drop( node, position );
						System.out.println( model.toString() );
						}
					catch ( ImsException ex )
						{
						ex.printStackTrace();
						}
					event.getDropTargetContext().dropComplete(true);
					return;
					}
				}
			} 
		
		System.out.println( "Drop rejected" );
		event.rejectDrop();
		}
	catch (IOException exception)
		{
		exception.printStackTrace();
		System.err.println( "Exception" + exception.getMessage());
		event.rejectDrop();
		} 
	catch (UnsupportedFlavorException ufException )
		{
		ufException.printStackTrace();
		System.err.println( "Exception" + ufException.getMessage());
		event.rejectDrop();
		}   
	}

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

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

  public void dragGestureRecognized( DragGestureEvent event)
	{
    Point p = event.getDragOrigin();
	 TreePath sourcepath = getPathForLocation( p.x, p.y );
	 DefaultMutableTreeNode sourcenode;
	 
    if ( sourcepath != null )
   	{
		sourcenode = (DefaultMutableTreeNode)sourcepath.getLastPathComponent();

      // as the name suggests, starts the dragging
      System.out.println( "Starting drag..." );
      dragSource.startDrag(event, DragSource.DefaultMoveDrop, (Transferable)sourcenode, this);
   	}
   else
   	{
      System.out.println( "nothing was selected");   
   	}
	}


	}
